00001 package org.gel.mauve;
00002
00003 import java.io.File;
00004 import java.net.URL;
00005 import java.util.ArrayList;
00006 import java.util.Collections;
00007 import java.util.Comparator;
00008 import java.util.HashMap;
00009 import java.util.LinkedList;
00010 import java.util.List;
00011 import java.util.ListIterator;
00012 import java.util.Vector;
00013
00014 import javax.swing.event.EventListenerList;
00015
00016 import org.gel.mauve.contigs.DefaultContigHandler;
00017
00028 public class BaseViewerModel {
00029
00030 protected Genome [] genomes;
00031
00032
00033 private Genome [] sourceGenomes;
00034
00035
00036 private ViewerMode mode = ViewerMode.NORMAL;
00037
00038
00039 protected EventListenerList listenerList = new EventListenerList ();
00040
00041 protected ModelEvent modelEvent = new ModelEvent (this);
00042
00043
00044 private long longestRange = -1;
00045
00046
00047 private ColorScheme colorScheme;
00048
00049
00050 private Vector matchVector = new Vector ();
00051
00052
00053 private LinkedList highBoxes = new LinkedList ();
00054
00055
00056 private Genome referenceGenome;
00057
00058
00059 private Genome highlightGenome;
00060
00061
00062 private long highlightCoordinate;
00063
00064
00065 private boolean drawMatches = true;
00066
00067
00068 private boolean drawChromosomeBoundaries = true;
00069
00070
00071 private boolean drawMouseHighlighting = true;
00072
00073
00074 private File src;
00075
00076
00077 private URL sourceURL = null;
00078
00079
00080 private Genome rangeHighlightGenome = null;
00081
00082
00083 private long rangeHighlightLeft = -1;
00084
00085
00086 private long rangeHighlightRight = -1;
00087
00088
00089 protected DefaultContigHandler contig_handler;
00090
00100 public BaseViewerModel (File src) {
00101 this.src = src;
00102 contig_handler = new DefaultContigHandler (this);
00103 }
00104
00110 public File getSrc () {
00111 return src;
00112 }
00113
00119 public void setSourceURL (URL url) {
00120 this.sourceURL = url;
00121 }
00122
00128 public URL getSourceURL () {
00129 return sourceURL;
00130 }
00131
00139 public void setSequenceCount (int sequenceCount) {
00140
00141 genomes = new Genome [sequenceCount];
00142 sourceGenomes = new Genome [sequenceCount];
00143 }
00144
00148 public int getSequenceCount () {
00149 return genomes.length;
00150 }
00151
00160 public Genome getGenomeByViewingIndex (int viewIndex) {
00161 return genomes[viewIndex];
00162 }
00163
00164 public Genome getGenomeBySourceIndex (int sourceIndex) {
00165 return sourceGenomes[sourceIndex];
00166 }
00167
00173 public Vector<Genome> getGenomes () {
00174 Vector ret = new Vector ();
00175 for (int i = 0; i < genomes.length; i++)
00176 ret.add (genomes[i]);
00177 return ret;
00178 }
00179
00180 public int numGenomes(){
00181 return genomes.length;
00182 }
00183
00192 public void setGenome (int viewIndex, Genome g) {
00193 genomes[viewIndex] = g;
00194 g.setViewIndex (viewIndex);
00195
00196 sourceGenomes[g.getSourceIndex ()] = g;
00197
00198
00199 if (longestRange < g.getLength ()) {
00200 longestRange = g.getLength ();
00201 }
00202
00203
00204 for (int i = 0; i < genomes.length; i++) {
00205 Genome genome = genomes[i];
00206 if (genome != null) {
00207 genome.setViewLength (longestRange);
00208 }
00209 }
00210 }
00211
00217 public int getMatchCount () {
00218 return matchVector.size ();
00219 }
00220
00227 public Match getMatch (int index) {
00228 return (Match) matchVector.elementAt (index);
00229 }
00230
00240 public Vector sortedMatches (Comparator c) {
00241 Vector sorted = (Vector) matchVector.clone ();
00242 if (c != null)
00243 Collections.sort (sorted, c);
00244 return sorted;
00245 }
00246
00253 public void addMatch (Match m) {
00254 matchVector.add (m);
00255 }
00256
00266 public void setColorScheme (ColorScheme colorScheme) {
00267 if (!colorScheme.equals (this.colorScheme)) {
00268 this.colorScheme = colorScheme;
00269 colorScheme.apply (this);
00270
00271 fireColorEvent ();
00272 }
00273 }
00274
00280 public ColorScheme getColorScheme () {
00281 return colorScheme;
00282 }
00283
00290 public void addModelListener (ModelListener l) {
00291 listenerList.add (ModelListener.class, l);
00292 }
00293
00300 public void removeModelListener (ModelListener l) {
00301 listenerList.remove (ModelListener.class, l);
00302 }
00303
00310 public void addHighlightListener (HighlightListener l) {
00311 listenerList.add (HighlightListener.class, l);
00312 }
00313
00320 public void removeHighlightListener (HighlightListener l) {
00321 listenerList.remove (HighlightListener.class, l);
00322 }
00323
00328 protected void fireHighlightEvent () {
00329 Object [] listeners = listenerList.getListenerList ();
00330 for (int i = listeners.length - 2; i >= 0; i -= 2) {
00331 if (listeners[i] == HighlightListener.class) {
00332 ((HighlightListener) listeners[i + 1])
00333 .highlightChanged (modelEvent);
00334 }
00335 }
00336 }
00337
00342 protected void fireColorEvent () {
00343 Object [] listeners = listenerList.getListenerList ();
00344 for (int i = listeners.length - 2; i >= 0; i -= 2) {
00345 if (listeners[i] == ModelListener.class) {
00346 ((ModelListener) listeners[i + 1]).colorChanged (modelEvent);
00347 }
00348 }
00349 }
00350
00355 protected void fireWeightEvent () {
00356 Object [] listeners = listenerList.getListenerList ();
00357 for (int i = listeners.length - 2; i >= 0; i -= 2) {
00358 if (listeners[i] == ModelListener.class) {
00359 ((ModelListener) listeners[i + 1]).weightChanged (modelEvent);
00360 }
00361 }
00362 }
00363
00368 protected void fireDrawingSettingsEvent () {
00369 Object [] listeners = listenerList.getListenerList ();
00370 for (int i = listeners.length - 2; i >= 0; i -= 2) {
00371 if (listeners[i] == ModelListener.class) {
00372 ((ModelListener) listeners[i + 1])
00373 .drawingSettingsChanged (modelEvent);
00374 }
00375 }
00376 }
00377
00382 protected void fireModeEvent () {
00383 Object [] listeners = listenerList.getListenerList ();
00384 for (int i = listeners.length - 2; i >= 0; i -= 2) {
00385 if (listeners[i] == ModelListener.class) {
00386 ((ModelListener) listeners[i + 1]).modeChanged (modelEvent);
00387 }
00388 }
00389 }
00390
00395 public void firePrintingStartEvent() {
00396 Object [] listeners = listenerList.getListenerList ();
00397 for (int i = listeners.length - 2; i >= 0; i -= 2) {
00398 if (listeners[i] == ModelListener.class) {
00399 ((ModelListener) listeners[i + 1])
00400 .printingStart (modelEvent);
00401 }
00402 }
00403 }
00404
00409 public void firePrintingEndEvent() {
00410 Object [] listeners = listenerList.getListenerList ();
00411 for (int i = listeners.length - 2; i >= 0; i -= 2) {
00412 if (listeners[i] == ModelListener.class) {
00413 ((ModelListener) listeners[i + 1])
00414 .printingEnd (modelEvent);
00415 }
00416 }
00417 }
00418
00423 public void fireViewableRangeEvent () {
00424 Object [] listeners = listenerList.getListenerList ();
00425 for (int i = listeners.length - 2; i >= 0; i -= 2) {
00426 if (listeners[i] == ModelListener.class) {
00427 ((ModelListener) listeners[i + 1])
00428 .viewableRangeChanged (modelEvent);
00429 }
00430 }
00431 }
00432
00437 protected void fireViewableRangeStartEvent () {
00438 Object [] listeners = listenerList.getListenerList ();
00439 for (int i = listeners.length - 2; i >= 0; i -= 2) {
00440 if (listeners[i] == ModelListener.class) {
00441 ((ModelListener) listeners[i + 1])
00442 .viewableRangeChangeStart (modelEvent);
00443 }
00444 }
00445 }
00446
00451 protected void fireViewableRangeEndEvent () {
00452 Object [] listeners = listenerList.getListenerList ();
00453 for (int i = listeners.length - 2; i >= 0; i -= 2) {
00454 if (listeners[i] == ModelListener.class) {
00455 ((ModelListener) listeners[i + 1])
00456 .viewableRangeChangeEnd (modelEvent);
00457 }
00458 }
00459 }
00460
00465 protected void fireReorderGenomeEvent () {
00466 Object [] listeners = listenerList.getListenerList ();
00467 for (int i = listeners.length - 2; i >= 0; i -= 2) {
00468 if (listeners[i] == ModelListener.class) {
00469 ((ModelListener) listeners[i + 1])
00470 .genomesReordered (modelEvent);
00471 }
00472 }
00473 }
00474
00479 protected void fireReferenceChangedEvent () {
00480 Object [] listeners = listenerList.getListenerList ();
00481 for (int i = listeners.length - 2; i >= 0; i -= 2) {
00482 if (listeners[i] == ModelListener.class) {
00483 ((ModelListener) listeners[i + 1])
00484 .referenceChanged (modelEvent);
00485 }
00486 }
00487 }
00488
00494 public ViewerMode getMode () {
00495 return mode;
00496 }
00497
00505 public void setMode (ViewerMode mode) {
00506 if (this.mode != mode) {
00507 this.mode = mode;
00508 fireModeEvent ();
00509 }
00510 }
00511
00525 public void reorderSequences (int [] new_order) {
00526
00527 Genome [] newGenomes = new Genome [genomes.length];
00528 for (int seqI = 0; seqI < genomes.length; seqI++) {
00529 newGenomes[seqI] = genomes[new_order[seqI]];
00530 newGenomes[seqI].setViewIndex (seqI);
00531 }
00532 genomes = newGenomes;
00533
00534 fireReorderGenomeEvent ();
00535 }
00536
00537 public void setReference (Genome g) {
00538 referenceGenome = g;
00539 referenceUpdated ();
00540 fireReferenceChangedEvent ();
00541 }
00542
00543 public Genome getReference () {
00544 return referenceGenome;
00545 }
00546
00547 protected void referenceUpdated () {
00548
00549 }
00550
00551 public void setVisible(Genome g, boolean visible)
00552 {
00553 if(g.getVisible() != visible )
00554 {
00555 g.setVisible(visible);
00556 fireGenomeVisibilityChangedEvent();
00557 }
00558 }
00559
00560 public void fireGenomeVisibilityChangedEvent()
00561 {
00562 Object[] listeners = listenerList.getListenerList();
00563 for (int i = listeners.length-2; i>=0; i-=2) {
00564 if (listeners[i]==ModelListener.class) {
00565 ((ModelListener)listeners[i+1]).genomeVisibilityChanged(modelEvent);
00566 }
00567 }
00568 }
00569
00570 private void correctMatchReversals () {
00571
00572 for (int matchI = 0; matchI < getMatchCount (); matchI++) {
00573 Match m = getMatch (matchI);
00574
00575
00576
00577 for (int seqI = 0; seqI < genomes.length; seqI++) {
00578 Genome g = getGenomeByViewingIndex (seqI);
00579
00580 if (m.getStart (g) != 0) {
00581 if (m.getReverse (g)) {
00582 for (int seqJ = seqI; seqJ < genomes.length; seqJ++) {
00583 Genome g2 = getGenomeByViewingIndex (seqJ);
00584 m.setReverse (g2, !m.getReverse (g2));
00585 }
00586 }
00587 break;
00588 }
00589 }
00590 }
00591 }
00592
00606 public void getMatchRange (Genome g, long start_coord, long end_coord,
00607 int [] match_range) {
00608 Vector sortedMatches = g.getSortedMatches ();
00609
00610 if (sortedMatches.size () == 0) {
00611 match_range[0] = -1;
00612 match_range[1] = -1;
00613 return;
00614 }
00615
00616 MatchStartComparator matchComparator = new MatchStartComparator (g);
00617 Match f_match = new Match ((Match) sortedMatches.get (0));
00618
00619 f_match.setStart (g, start_coord);
00620 if (f_match.getStart (g) < 1)
00621 f_match.setStart (g, 1);
00622
00623 int match_startI = Collections.binarySearch (sortedMatches, f_match,
00624 matchComparator);
00625 match_startI = match_startI >= 0 ? match_startI : -match_startI - 1;
00626
00627 f_match.setStart (g, end_coord + 1);
00628 int match_endI = Collections.binarySearch (sortedMatches, f_match,
00629 matchComparator);
00630 match_endI = match_endI >= 0 ? match_endI : -match_endI - 1;
00631
00632
00633 if (match_startI > 0) {
00634 Match prev_match = (Match) sortedMatches.get (match_startI - 1);
00635
00636 if (prev_match.getStart (g) + prev_match.getLength (g) > start_coord
00637 && prev_match.getStart (g) != Match.NO_MATCH)
00638 match_startI--;
00639 }
00640 match_range[0] = match_startI;
00641 match_range[1] = match_endI;
00642 }
00643
00650 public void addMatchHighlight (Match highlighted_box) {
00651 ListIterator high_iter = highBoxes.listIterator ();
00652 while (high_iter.hasNext ()) {
00653 if (high_iter.next () == highlighted_box) {
00654 return;
00655 }
00656 }
00657 highlighted_box.highlighted = true;
00658 highBoxes.addLast (highlighted_box);
00659
00660 fireHighlightEvent ();
00661 }
00662
00663 public Match lastMatchHighlight () {
00664 if (highBoxes.isEmpty ())
00665 return null;
00666
00667 return (Match) highBoxes.getLast ();
00668
00669 }
00670
00674 public void clearMatchHighlights () {
00675 ListIterator high_iter = highBoxes.listIterator ();
00676 while (high_iter.hasNext ()) {
00677 Match next_box = (Match) high_iter.next ();
00678 next_box.highlighted = false;
00679 }
00680 highBoxes.clear ();
00681
00682 fireHighlightEvent ();
00683 }
00684
00685 public long getHighlightCoordinate () {
00686 return highlightCoordinate;
00687 }
00688
00689 public Genome getHighlightGenome () {
00690 return highlightGenome;
00691 }
00692
00693 public long getRangeHighlightLeft () {
00694 return rangeHighlightLeft;
00695 }
00696
00697 public long getRangeHighlightRight () {
00698 return rangeHighlightRight;
00699 }
00700
00701 public Genome getRangeHighlightGenome () {
00702 return rangeHighlightGenome;
00703 }
00704
00705 public void updateHighlight (Genome g, long coordinate) {
00706 highlightGenome = g;
00707 highlightCoordinate = coordinate;
00708 fireHighlightEvent ();
00709 }
00710
00711 public void setDrawMatches (boolean value) {
00712 if (value != drawMatches) {
00713 this.drawMatches = value;
00714 this.fireDrawingSettingsEvent ();
00715 }
00716 }
00717
00718 public boolean getDrawMatches () {
00719 return drawMatches;
00720 }
00721
00722 public void setDrawChromosomeBoundaries (boolean value) {
00723 if (value != drawChromosomeBoundaries) {
00724 this.drawChromosomeBoundaries = value;
00725 this.fireDrawingSettingsEvent ();
00726 }
00727 }
00728
00729 public boolean getDrawChromosomeBoundaries () {
00730 return drawChromosomeBoundaries;
00731 }
00732
00733 public void setDrawMouseCursor (boolean value) {
00734 if (value != drawMouseHighlighting) {
00735 this.drawMouseHighlighting = value;
00736 this.fireDrawingSettingsEvent ();
00737 }
00738 }
00739
00740 public boolean getDrawMouseHighlighting () {
00741 return drawMouseHighlighting;
00742 }
00743
00744 public void setFocus (String sequenceID, long start, long end, String contig) {
00745 Genome g = null;
00746 for (int i = 0; i < genomes.length; i++) {
00747 if (sequenceID.equals (genomes[i].getID ())) {
00748 g = genomes[i];
00749 break;
00750 }
00751 }
00752 if (g == null) {
00753 System.err
00754 .println ("Received focus request for nonexistent sequence id "
00755 + sequenceID);
00756 return;
00757 }
00758 if (contig != null) {
00759 start = contig_handler.getPseudoCoord(g.getSourceIndex(), start, contig);
00760 end = contig_handler.getPseudoCoord(g.getSourceIndex(), end, contig);
00761 }
00762 long len = (end - start) * 5;
00763 int zoom = (int) (100 * g.getViewLength () / (double) len);
00764 long center = start + ((end - start) / 2);
00765 zoomAndCenter (g, zoom, center);
00766
00767 highlightRange (g, start, end);
00768 }
00769
00775 public void alignView (long [] align_coords, Genome selected) {
00776 fireViewableRangeStartEvent ();
00777
00778
00779
00780 long start_offset = align_coords[selected.getSourceIndex ()]
00781 - selected.getViewStart ();
00782 for (int seqI = 0; seqI < getSequenceCount (); seqI++) {
00783 if (seqI != selected.getSourceIndex ()
00784 && align_coords[seqI] != Match.NO_MATCH) {
00785 Genome g = getGenomeBySourceIndex (seqI);
00786 g.setViewStart (align_coords[seqI] - start_offset);
00787 g.setViewLength (selected.getViewLength ());
00788 }
00789 }
00790 fireViewableRangeEvent ();
00791
00792 fireViewableRangeEndEvent ();
00793 }
00794
00795 public void alignView (Match align_match, Genome g) {
00796 long [] align_coords = new long [getSequenceCount ()];
00797
00798 for (int i = 0; i < getSequenceCount (); i++) {
00799 align_coords[i] = align_match.getStart (getGenomeBySourceIndex (i));
00800 }
00801
00802 alignView (align_coords, g);
00803 }
00804
00819 public void zoomAndMove (int zoom_percent, int move_percent) {
00820 for (int i = 0; i < genomes.length; i++) {
00821 zoomAndMove (genomes[i], zoom_percent, move_percent);
00822 }
00823 }
00824
00825 public void zoomAndMove (int zoom_percent, long offset) {
00826 for (int i = 0; i < genomes.length; i++) {
00827 zoomAndMove (genomes[i], zoom_percent, offset);
00828 }
00829 }
00830
00845 public void zoomAndMove (Genome g, int zoom_percent, int move_percent) {
00846
00847 if (move_percent != 0) {
00848 double move = ((double) g.getViewLength ()) * (move_percent / 100d);
00849 if (Math.abs (move) < 1) {
00850 move = (move < 0) ? -1 : 1;
00851 }
00852 zoomAndMove (g, zoom_percent, (long) move);
00853 } else {
00854 zoomAndMove (g, zoom_percent, 0L);
00855 }
00856 }
00857
00858 private void zoomAndMove (Genome g, int zoom_percent, long offset) {
00859 fireViewableRangeStartEvent ();
00860
00861
00862 if (offset != 0) {
00863
00864 long new_view_start = g.getViewStart () + offset;
00865
00866
00867 if (new_view_start + g.getViewLength () < 1) {
00868 new_view_start = 1 - g.getViewLength ();
00869 } else if (new_view_start > g.getLength ()) {
00870 new_view_start = g.getLength ();
00871 }
00872 g.setViewStart (new_view_start);
00873 }
00874
00875 if (zoom_percent == 0) {
00876
00877 g.setViewStart (1);
00878 g.setViewLength (longestRange);
00879 } else if (zoom_percent != 100) {
00880
00881 long new_view_length = (long) ((100d * g.getViewLength ()) / zoom_percent);
00882
00883 if (new_view_length < 5)
00884 new_view_length = 5;
00885 if (new_view_length > longestRange)
00886 new_view_length = longestRange;
00887
00888 long new_view_start = g.getViewStart ()
00889 + ((g.getViewLength () - new_view_length) / 2);
00890
00891
00892 if (new_view_start + new_view_length < 1)
00893 new_view_start = 1 - g.getViewLength ();
00894 else if (new_view_start > g.getLength ())
00895 new_view_start = g.getLength ();
00896
00897 g.setViewStart (new_view_start);
00898 g.setViewLength (new_view_length);
00899 }
00900
00901 fireViewableRangeEvent ();
00902
00903 fireViewableRangeEndEvent ();
00904 }
00905
00906 public void zoomAndCenter (Genome g, int zoom_percent, long coord) {
00907 long offset = coord - (g.getViewStart () + (g.getViewLength () / 2));
00908 zoomAndMove (zoom_percent, offset);
00909 }
00910
00912 public void highlightRange (Genome g, long left_end, long right_end) {
00913 rangeHighlightGenome = g;
00914 rangeHighlightLeft = left_end;
00915 rangeHighlightRight = right_end;
00916 fireHighlightEvent ();
00917 }
00918
00919 private HashMap<Genome,List> attributes = new HashMap<Genome,List>();
00920 public void addGenomeAttribute(Genome g, Object o){
00921 List l = attributes.get(g);
00922 if(l==null){
00923 l = new ArrayList();
00924 attributes.put(g,l);
00925 }
00926 l.add(o);
00927 fireAttributesEvent();
00928 }
00929 public List getGenomeAttributes(Genome g){
00930 return attributes.get(g);
00931 }
00932 boolean drawAttributes = false;
00933 public boolean getDrawAttributes() {
00934 return drawAttributes;
00935 }
00936 public void setDrawAttributes(boolean drawAttributes) {
00937 this.drawAttributes = drawAttributes;
00938 fireAttributesEvent();
00939 }
00940
00945 protected void fireAttributesEvent () {
00946 Object [] listeners = listenerList.getListenerList ();
00947 for (int i = listeners.length - 2; i >= 0; i -= 2) {
00948 if (listeners[i] == ModelListener.class) {
00949 ((ModelListener) listeners[i + 1]).attributesChanged (modelEvent);
00950 }
00951 }
00952 }
00953
00954 }