After merge
[jalview.git] / src / jalview / gui / SeqPanel.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 package jalview.gui;\r
20 \r
21 import jalview.datamodel.*;\r
22 \r
23 import jalview.schemes.*;\r
24 \r
25 import java.awt.*;\r
26 import java.awt.event.*;\r
27 \r
28 import java.util.*;\r
29 \r
30 import javax.swing.*;\r
31 \r
32 \r
33 /**\r
34  * DOCUMENT ME!\r
35  *\r
36  * @author $author$\r
37  * @version $Revision$\r
38  */\r
39 public class SeqPanel extends JPanel\r
40 {\r
41     /** DOCUMENT ME!! */\r
42     public SeqCanvas seqCanvas;\r
43 \r
44     /** DOCUMENT ME!! */\r
45     public AlignmentPanel ap;\r
46     protected int lastres;\r
47     protected int startseq;\r
48     int startEdit = -1;\r
49     int endEdit = -1;\r
50     protected AlignViewport av;\r
51 \r
52     // if character is inserted or deleted, we will need to recalculate the conservation\r
53     int seqEditOccurred = -1;\r
54     ScrollThread scrollThread = null;\r
55     boolean mouseDragging = false;\r
56     boolean editingSeqs = false;\r
57     boolean groupEditing = false;\r
58 \r
59     //////////////////////////////////////////\r
60     /////Everything below this is for defining the boundary of the rubberband\r
61     //////////////////////////////////////////\r
62     int oldSeq = -1;\r
63     boolean changeEndSeq = false;\r
64     boolean changeStartSeq = false;\r
65     boolean changeEndRes = false;\r
66     boolean changeStartRes = false;\r
67     SequenceGroup stretchGroup = null;\r
68     boolean remove = false;\r
69 \r
70     boolean mouseWheelPressed = false;\r
71 \r
72     /**\r
73      * Creates a new SeqPanel object.\r
74      *\r
75      * @param avp DOCUMENT ME!\r
76      * @param p DOCUMENT ME!\r
77      */\r
78     public SeqPanel(AlignViewport avp, AlignmentPanel p)\r
79     {\r
80         ToolTipManager.sharedInstance().registerComponent(this);\r
81         ToolTipManager.sharedInstance().setInitialDelay(0);\r
82         ToolTipManager.sharedInstance().setDismissDelay(10000);\r
83         this.av = avp;\r
84         setBackground(Color.white);\r
85 \r
86         seqCanvas = new SeqCanvas(avp);\r
87         setLayout(new BorderLayout());\r
88         add(seqCanvas, BorderLayout.CENTER);\r
89 \r
90         ap = p;\r
91 \r
92 \r
93         addMouseMotionListener(new MouseMotionAdapter()\r
94             {\r
95                 public void mouseMoved(MouseEvent evt)\r
96                 {\r
97                     doMouseMoved(evt);\r
98                     if (editingSeqs)\r
99                     {\r
100                       // This is because MacOSX creates a mouseMoved\r
101                       // If control is down\r
102                       if(!av.isDataset())\r
103                         doMouseDragged(evt);\r
104                     }\r
105                 }\r
106 \r
107                 public void mouseDragged(MouseEvent evt)\r
108                 {\r
109                     if (editingSeqs)\r
110                     {\r
111                       if(!av.isDataset())\r
112                         doMouseDragged(evt);\r
113                     }\r
114                     else\r
115                     {\r
116                       if(!av.isDataset())\r
117                         doMouseDraggedDefineMode(evt);\r
118                     }\r
119                 }\r
120             });\r
121 \r
122        addMouseWheelListener(new MouseWheelListener()\r
123        {\r
124          public void mouseWheelMoved(MouseWheelEvent e)\r
125          {\r
126 \r
127            if (mouseWheelPressed)\r
128            {\r
129              Font font = av.getFont();\r
130              int fontSize = font.getSize();\r
131              if (e.getWheelRotation() > 0 && fontSize < 51)\r
132                fontSize++;\r
133              else if (fontSize > 1)\r
134                fontSize--;\r
135 \r
136              av.setFont(new Font(font.getName(), font.getStyle(), fontSize));\r
137              ap.fontChanged();\r
138            }\r
139            else\r
140            {\r
141              if (e.getWheelRotation() > 0)\r
142                ap.scrollUp(false);\r
143              else\r
144                ap.scrollUp(true);\r
145            }\r
146 \r
147          }\r
148        });\r
149 \r
150 \r
151        if(!av.isDataset())\r
152        {\r
153          addMouseListener(new MouseAdapter()\r
154          {\r
155            public void mouseReleased(MouseEvent evt)\r
156            {\r
157              mouseWheelPressed = false;\r
158 \r
159              if (editingSeqs)\r
160              {\r
161                doMouseReleased(evt);\r
162              }\r
163              else\r
164              {\r
165                doMouseReleasedDefineMode(evt);\r
166              }\r
167            }\r
168 \r
169            public void mousePressed(MouseEvent evt)\r
170            {\r
171              if (javax.swing.SwingUtilities.isMiddleMouseButton(evt))\r
172              {\r
173                mouseWheelPressed = true;\r
174                return;\r
175              }\r
176 \r
177              if (evt.isShiftDown() || evt.isAltDown() ||\r
178                  evt.isControlDown())\r
179              {\r
180                if (evt.isAltDown() || evt.isControlDown())\r
181                {\r
182                  groupEditing = true;\r
183 \r
184                }\r
185 \r
186                editingSeqs = true;\r
187                doMousePressed(evt);\r
188              }\r
189              else\r
190              {\r
191                doMousePressedDefineMode(evt);\r
192              }\r
193            }\r
194 \r
195            public void mouseExited(MouseEvent evt)\r
196            {\r
197              if (editingSeqs)\r
198              {\r
199                return;\r
200              }\r
201 \r
202              doMouseExitedDefineMode(evt);\r
203            }\r
204 \r
205            public void mouseEntered(MouseEvent evt)\r
206            {\r
207              if (editingSeqs)\r
208              {\r
209                return;\r
210              }\r
211 \r
212              doMouseEnteredDefineMode(evt);\r
213            }\r
214          });\r
215        }\r
216     }\r
217 \r
218     int startWrapBlock=-1;\r
219     int wrappedBlock=-1;\r
220     int findRes(MouseEvent evt)\r
221    {\r
222      int res = 0;\r
223      int x = evt.getX();\r
224 \r
225     if (av.wrapAlignment)\r
226     {\r
227 \r
228       int hgap = av.charHeight;\r
229       if (av.scaleAboveWrapped)\r
230         hgap += av.charHeight;\r
231 \r
232       int cHeight = av.getAlignment().getHeight() * av.charHeight\r
233           + hgap + seqCanvas.getAnnotationHeight();\r
234 \r
235         int y = evt.getY();\r
236         y -= hgap;\r
237         x -= seqCanvas.LABEL_WEST;\r
238 \r
239 \r
240         int cwidth = seqCanvas.getWrappedCanvasWidth(this.getWidth());\r
241 \r
242         wrappedBlock = y / cHeight;\r
243         wrappedBlock += av.getStartRes() / cwidth;\r
244 \r
245         res = wrappedBlock * cwidth + x / av.getCharWidth();\r
246 \r
247     }\r
248     else\r
249     {\r
250         res = (x / av.getCharWidth()) + av.getStartRes();\r
251     }\r
252 \r
253     return res;\r
254 \r
255    }\r
256 \r
257    int findSeq(MouseEvent evt)\r
258    {\r
259 \r
260      int seq = 0;\r
261      int y = evt.getY();\r
262 \r
263      if (av.wrapAlignment)\r
264      {\r
265        int hgap = av.charHeight;\r
266        if (av.scaleAboveWrapped)\r
267          hgap += av.charHeight;\r
268 \r
269        int cHeight = av.getAlignment().getHeight() * av.charHeight\r
270            + hgap + seqCanvas.getAnnotationHeight();\r
271 \r
272          y -= hgap;\r
273 \r
274        seq = ( (y % cHeight) / av.getCharHeight());\r
275      }\r
276      else\r
277      {\r
278        seq = (y / av.getCharHeight()) + av.getStartSeq();\r
279      }\r
280 \r
281      return seq;\r
282    }\r
283 \r
284 \r
285     /**\r
286      * DOCUMENT ME!\r
287      *\r
288      * @param evt DOCUMENT ME!\r
289      */\r
290     public void doMouseReleased(MouseEvent evt)\r
291     {\r
292         if (seqEditOccurred > -1)\r
293         {\r
294             editOccurred(seqEditOccurred);\r
295         }\r
296 \r
297         startseq = -1;\r
298         lastres = -1;\r
299         seqEditOccurred = -1;\r
300         editingSeqs = false;\r
301         groupEditing = false;\r
302 \r
303         ap.repaint();\r
304     }\r
305 \r
306     /**\r
307      * DOCUMENT ME!\r
308      *\r
309      * @param evt DOCUMENT ME!\r
310      */\r
311     public void doMousePressed(MouseEvent evt)\r
312     {\r
313       ap.alignFrame.addHistoryItem(new HistoryItem("Edit Sequence",\r
314                                                    av.alignment, HistoryItem.EDIT));\r
315 \r
316       int seq = findSeq(evt);\r
317       int res = findRes(evt);\r
318 \r
319       if(seq<0 || res<0)\r
320         return;\r
321 \r
322         if ((seq < av.getAlignment().getHeight()) &&\r
323                 (res < av.getAlignment().getSequenceAt(seq).getLength()))\r
324         {\r
325             startseq = seq;\r
326             lastres = res;\r
327         }\r
328         else\r
329         {\r
330             startseq = -1;\r
331             lastres = -1;\r
332         }\r
333 \r
334         startEdit = lastres;\r
335         endEdit = lastres;\r
336 \r
337         return;\r
338     }\r
339 \r
340     /**\r
341      * DOCUMENT ME!\r
342      *\r
343      * @param evt DOCUMENT ME!\r
344      */\r
345     public void doMouseMoved(MouseEvent evt)\r
346     {\r
347       int res = findRes(evt);\r
348       int seq = findSeq(evt);\r
349 \r
350       if(res<0 || seq<0 || seq >= av.getAlignment().getHeight())\r
351             return;\r
352 \r
353       SequenceI sequence = av.getAlignment().getSequenceAt(seq);\r
354 \r
355       if (res > sequence.getLength())\r
356       {\r
357         return;\r
358       }\r
359 \r
360       if(seqCanvas.pdbCanvas!=null && sequence==seqCanvas.pdbCanvas.sequence)\r
361       {\r
362         seqCanvas.pdbCanvas.highlightRes(sequence.findPosition(res));\r
363       }\r
364 \r
365 \r
366         StringBuffer text = new StringBuffer("Sequence " + (seq + 1) + " ID: " +\r
367                 sequence.getName());\r
368 \r
369         Object obj = null;\r
370         if (av.alignment.isNucleotide())\r
371         {\r
372           obj = ResidueProperties.nucleotideName.get(sequence.getCharAt(res) +\r
373               "");\r
374           if(obj!=null)\r
375             text.append(" Nucleotide: ");\r
376         }\r
377         else\r
378         {\r
379           obj = ResidueProperties.aa2Triplet.get(sequence.getCharAt(res) + "");\r
380           if(obj!=null)\r
381             text.append("  Residue: ");\r
382         }\r
383 \r
384         if (obj != null)\r
385         {\r
386 \r
387           if (obj != "")\r
388           {\r
389             text.append( obj + " (" +\r
390                         av.getAlignment().getSequenceAt(seq).findPosition(res) + ")");\r
391           }\r
392         }\r
393 \r
394         ap.alignFrame.statusBar.setText(text.toString());\r
395 \r
396         // use aa to see if the mouse pointer is on a\r
397         if (av.showSequenceFeatures)\r
398         {\r
399             Vector features = sequence.getDatasetSequence().getSequenceFeatures();\r
400             if(features!=null)\r
401             {\r
402               StringBuffer sbuffer = new StringBuffer("<html>");\r
403 \r
404               for (int i = 0; i < features.size(); i++)\r
405               {\r
406                 SequenceFeature sf = (SequenceFeature) features.elementAt(i);\r
407 \r
408                 if ( (sf.getBegin() <= sequence.findPosition(res)) &&\r
409                     (sf.getEnd() >= sequence.findPosition(res)))\r
410                 {\r
411                   if (sf.getType().equals("disulfide bond"))\r
412                   {\r
413                     if (sf.getBegin() == sequence.findPosition(res)\r
414                         || sf.getEnd() == sequence.findPosition(res))\r
415                     {\r
416                       if (sbuffer.length() > 6)\r
417                         sbuffer.append("<br>");\r
418                       sbuffer.append("disulfide bond " + sf.getBegin() + ":" +\r
419                                      sf.getEnd());\r
420                     }\r
421                   }\r
422                   else\r
423                   {\r
424                     if (sbuffer.length() > 6)\r
425                       sbuffer.append("<br>");\r
426                     sbuffer.append(sf.getType());\r
427                     if (sf.getDescription() != null)\r
428                       sbuffer.append(" " + sf.getDescription());\r
429 \r
430                     if (sf.getStatus() != null)\r
431                     {\r
432                       sbuffer.append(" (" + sf.getStatus() + ")");\r
433                     }\r
434                   }\r
435                 }\r
436 \r
437               }\r
438 \r
439               sbuffer.append("</html>");\r
440               if(sbuffer.length()==13) // <html></html>\r
441                 setToolTipText("");\r
442               else\r
443                setToolTipText(sbuffer.toString());\r
444             }\r
445             else\r
446               setToolTipText("");\r
447         }\r
448     }\r
449 \r
450     /**\r
451      * DOCUMENT ME!\r
452      *\r
453      * @param evt DOCUMENT ME!\r
454      */\r
455     public void doMouseDragged(MouseEvent evt)\r
456     {\r
457         // If we're dragging we're editing\r
458         int res = findRes(evt);\r
459 \r
460         if (res < 0)\r
461         {\r
462             res = 0;\r
463         }\r
464 \r
465         if ((lastres == -1) || (lastres == res))\r
466         {\r
467             return;\r
468         }\r
469 \r
470         boolean dragRight = true;\r
471 \r
472         if ((res < av.getAlignment().getWidth()) && (res < lastres))\r
473         {\r
474             dragRight = false;\r
475         }\r
476 \r
477         if (res != lastres)\r
478         {\r
479             // Group editing\r
480             if (groupEditing)\r
481             {\r
482                 SequenceGroup sg = av.getSelectionGroup();\r
483 \r
484                 if (sg == null)\r
485                 {\r
486                     lastres = -1;\r
487 \r
488                     return;\r
489                 }\r
490 \r
491                 // drag to right\r
492                 if (dragRight)\r
493                 {\r
494                     sg.setEndRes(sg.getEndRes() + (res - lastres));\r
495                 }\r
496 \r
497                 // drag to left\r
498                 else\r
499                 {\r
500                     /// Are we able to delete?\r
501                     // ie are all columns blank?\r
502                     boolean deleteAllowed = false;\r
503 \r
504                     for (int s = 0; s < sg.getSize(); s++)\r
505                     {\r
506                         SequenceI seq = sg.getSequenceAt(s);\r
507 \r
508                         for (int j = res; j < lastres; j++)\r
509                         {\r
510                             if (seq.getSequence().length() <= j)\r
511                             {\r
512                                 continue;\r
513                             }\r
514 \r
515                             if (!jalview.util.Comparison.isGap(\r
516                                         seq.getSequence().charAt(j)))\r
517                             {\r
518                                 // Not a gap, block edit not valid\r
519                                 res = j + 1;\r
520                                 deleteAllowed = false;\r
521 \r
522                                 continue;\r
523                             }\r
524 \r
525                             deleteAllowed = true;\r
526                         }\r
527                     }\r
528 \r
529                     if (!deleteAllowed)\r
530                     {\r
531                         lastres = -1;\r
532 \r
533                         return;\r
534                     }\r
535 \r
536                     sg.setEndRes(sg.getEndRes() - (lastres - res));\r
537                 }\r
538 \r
539                 for (int i = 0; i < sg.getSize(); i++)\r
540                 {\r
541                     SequenceI s = sg.getSequenceAt(i);\r
542                     int k = av.alignment.findIndex(s);\r
543 \r
544                     // drag to right\r
545                     if (dragRight)\r
546                     {\r
547                         for (int j = lastres; j < res; j++)\r
548                         {\r
549                             insertChar(j, k);\r
550                         }\r
551                     }\r
552 \r
553                     // drag to left\r
554                     else\r
555                     {\r
556                         for (int j = res; j < lastres; j++)\r
557                         {\r
558                             if (s.getLength() > j)\r
559                             {\r
560                                 deleteChar(res, k);\r
561                             }\r
562                         }\r
563                     }\r
564                 }\r
565             }\r
566             else /////Editing a single sequence///////////\r
567             {\r
568                 if ((res < av.getAlignment().getWidth()) && (res > lastres))\r
569                 {\r
570                     // dragging to the right\r
571                     for (int j = lastres; j < res; j++)\r
572                     {\r
573                         insertChar(j, startseq);\r
574                     }\r
575                 }\r
576                 else if ((res < av.getAlignment().getWidth()) &&\r
577                         (res < lastres))\r
578                 {\r
579                     // dragging to the left\r
580                     for (int j = lastres; j > res; j--)\r
581                     {\r
582                         if (jalview.util.Comparison.isGap(\r
583                                     av.alignment.getSequenceAt(startseq)\r
584                                                     .getSequence().charAt(res)))\r
585                         {\r
586                             deleteChar(res, startseq);\r
587                         }\r
588                         else\r
589                         {\r
590                             break;\r
591                         }\r
592                     }\r
593                 }\r
594             }\r
595         }\r
596 \r
597         endEdit = res;\r
598         lastres = res;\r
599         seqCanvas.repaint();\r
600     }\r
601 \r
602     /**\r
603      * DOCUMENT ME!\r
604      *\r
605      * @param seqstart DOCUMENT ME!\r
606      * @param seqend DOCUMENT ME!\r
607      * @param start DOCUMENT ME!\r
608      */\r
609     public void drawChars(int seqstart, int seqend, int start)\r
610     {\r
611         seqCanvas.drawPanel(seqCanvas.gg, start, av.getEndRes(), seqstart,\r
612             seqend, av.getStartRes(), av.getStartSeq(), 0);\r
613         seqCanvas.repaint();\r
614     }\r
615 \r
616     /**\r
617      * DOCUMENT ME!\r
618      *\r
619      * @param j DOCUMENT ME!\r
620      * @param seq DOCUMENT ME!\r
621      */\r
622     public void insertChar(int j, int seq)\r
623     {\r
624         av.alignment.getSequenceAt(seq).insertCharAt(j, av.getGapCharacter());\r
625         seqEditOccurred = seq;\r
626     }\r
627 \r
628     /**\r
629      * DOCUMENT ME!\r
630      *\r
631      * @param j DOCUMENT ME!\r
632      * @param seq DOCUMENT ME!\r
633      */\r
634     public void deleteChar(int j, int seq)\r
635     {\r
636         av.alignment.getSequenceAt(seq).deleteCharAt(j);\r
637         seqEditOccurred = seq;\r
638 \r
639         av.alignment.getWidth();\r
640         seqCanvas.repaint();\r
641     }\r
642 \r
643     /**\r
644      * DOCUMENT ME!\r
645      *\r
646      * @param i DOCUMENT ME!\r
647      */\r
648     void editOccurred(int i)\r
649     {\r
650       if (endEdit == startEdit)\r
651       {\r
652         ap.alignFrame.historyList.pop();\r
653         ap.alignFrame.updateEditMenuBar();\r
654       }\r
655 \r
656       av.firePropertyChange("alignment", null,av.getAlignment().getSequences());\r
657 \r
658     }\r
659 \r
660     /**\r
661      * DOCUMENT ME!\r
662      *\r
663      * @param evt DOCUMENT ME!\r
664      */\r
665     public void doMousePressedDefineMode(MouseEvent evt)\r
666     {\r
667       int res = findRes(evt);\r
668       int seq = findSeq(evt);\r
669       oldSeq = seq;\r
670 \r
671       startWrapBlock=wrappedBlock;\r
672 \r
673       if(av.wrapAlignment && seq>av.alignment.getHeight())\r
674       {\r
675           JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
676               "Cannot edit annotations in wrapped view.",\r
677               "Wrapped view - no edit",\r
678               JOptionPane.WARNING_MESSAGE);\r
679         return;\r
680       }\r
681 \r
682       if(seq<0 || res<0)\r
683             return;\r
684 \r
685 \r
686         SequenceI sequence = (Sequence) av.getAlignment().getSequenceAt(seq);\r
687 \r
688         if ((sequence == null) || (res > sequence.getLength()))\r
689         {\r
690             return;\r
691         }\r
692 \r
693         stretchGroup = av.getSelectionGroup();\r
694 \r
695         if (stretchGroup == null)\r
696         {\r
697             stretchGroup = av.alignment.findGroup(sequence);\r
698 \r
699             if ((stretchGroup != null) && (res > stretchGroup.getStartRes()) &&\r
700                     (res < stretchGroup.getEndRes()))\r
701             {\r
702                 av.setSelectionGroup(stretchGroup);\r
703             }\r
704             else\r
705             {\r
706                 stretchGroup = null;\r
707             }\r
708         }\r
709         else if (!stretchGroup.sequences.contains(sequence) ||\r
710                 (stretchGroup.getStartRes() > res) ||\r
711                 (stretchGroup.getEndRes() < res))\r
712         {\r
713             stretchGroup = null;\r
714 \r
715             SequenceGroup[] allGroups = av.alignment.findAllGroups(sequence);\r
716 \r
717             if (allGroups != null)\r
718             {\r
719                 for (int i = 0; i < allGroups.length; i++)\r
720                 {\r
721                     if ((allGroups[i].getStartRes() <= res) &&\r
722                             (allGroups[i].getEndRes() >= res))\r
723                     {\r
724                         stretchGroup = allGroups[i];\r
725                         av.setSelectionGroup(stretchGroup);\r
726 \r
727                         break;\r
728                     }\r
729                 }\r
730             }\r
731         }\r
732 \r
733         if (stretchGroup == null)\r
734         {\r
735             // define a new group here\r
736             SequenceGroup sg = new SequenceGroup();\r
737             sg.setStartRes(res);\r
738             sg.setEndRes(res);\r
739             sg.addSequence(sequence, false);\r
740             av.setSelectionGroup(sg);\r
741             stretchGroup = sg;\r
742 \r
743             if (av.getConservationSelected())\r
744             {\r
745                 SliderPanel.setConservationSlider(ap,\r
746                     av.getGlobalColourScheme(), "Background");\r
747             }\r
748 \r
749             if (av.getAbovePIDThreshold())\r
750             {\r
751                 SliderPanel.setPIDSliderSource(ap, av.getGlobalColourScheme(),\r
752                     "Background");\r
753             }\r
754         }\r
755         else if (javax.swing.SwingUtilities.isRightMouseButton(evt))\r
756         {\r
757             jalview.gui.PopupMenu pop = new jalview.gui.PopupMenu(ap, null);\r
758             pop.show(this, evt.getX(), evt.getY());\r
759 \r
760             // edit the properties of existing group\r
761         }\r
762 \r
763         if ((stretchGroup != null) && (stretchGroup.getEndRes() == res))\r
764         {\r
765             // Edit end res position of selected group\r
766             changeEndRes = true;\r
767         }\r
768         else if ((stretchGroup != null) && (stretchGroup.getStartRes() == res))\r
769         {\r
770             // Edit end res position of selected group\r
771             changeStartRes = true;\r
772         }\r
773 \r
774         stretchGroup.getWidth();\r
775 \r
776         seqCanvas.repaint();\r
777     }\r
778 \r
779     /**\r
780      * DOCUMENT ME!\r
781      *\r
782      * @param evt DOCUMENT ME!\r
783      */\r
784     public void doMouseReleasedDefineMode(MouseEvent evt)\r
785     {\r
786         if (mouseDragging)\r
787         {\r
788             stretchGroup.recalcConservation();\r
789             mouseDragging = false;\r
790         }\r
791 \r
792         if (stretchGroup == null)\r
793         {\r
794             return;\r
795         }\r
796 \r
797         if(stretchGroup.cs!=null)\r
798         {\r
799           if (stretchGroup.cs instanceof ClustalxColourScheme)\r
800           {\r
801             ( (ClustalxColourScheme) stretchGroup.cs).resetClustalX(stretchGroup.\r
802                 sequences,\r
803                 stretchGroup.getWidth());\r
804           }\r
805 \r
806           if (stretchGroup.cs.conservationApplied())\r
807           {\r
808             SliderPanel.setConservationSlider(ap, stretchGroup.cs,\r
809                                               stretchGroup.getName());\r
810           }\r
811           else\r
812           {\r
813             SliderPanel.setPIDSliderSource(ap, stretchGroup.cs,\r
814                                            stretchGroup.getName());\r
815           }\r
816         }\r
817         changeEndRes = false;\r
818         changeStartRes = false;\r
819         stretchGroup = null;\r
820         PaintRefresher.Refresh(av.alignment);\r
821     }\r
822 \r
823     /**\r
824      * DOCUMENT ME!\r
825      *\r
826      * @param evt DOCUMENT ME!\r
827      */\r
828     public void doMouseDraggedDefineMode(MouseEvent evt)\r
829     {\r
830       int res = findRes(evt);\r
831       int y = findSeq(evt);\r
832 \r
833       if(wrappedBlock!=startWrapBlock)\r
834         return;\r
835 \r
836       if (stretchGroup == null)\r
837       {\r
838             return;\r
839         }\r
840 \r
841         if (res > av.alignment.getWidth())\r
842         {\r
843             res = av.alignment.getWidth() - 1;\r
844         }\r
845 \r
846         if (stretchGroup.getEndRes() == res)\r
847         {\r
848             // Edit end res position of selected group\r
849             changeEndRes = true;\r
850         }\r
851         else if (stretchGroup.getStartRes() == res)\r
852         {\r
853             // Edit start res position of selected group\r
854             changeStartRes = true;\r
855         }\r
856 \r
857         if (res < av.getStartRes())\r
858         {\r
859             res = av.getStartRes();\r
860         }\r
861         else if (res > av.getEndRes() && !av.getWrapAlignment())\r
862         {\r
863             res = av.getEndRes();\r
864         }\r
865 \r
866         if (changeEndRes)\r
867         {\r
868             if (res > (stretchGroup.getStartRes() - 1))\r
869             {\r
870                 stretchGroup.setEndRes(res);\r
871             }\r
872         }\r
873         else if (changeStartRes)\r
874         {\r
875             if (res < (stretchGroup.getEndRes() + 1))\r
876             {\r
877                 stretchGroup.setStartRes(res);\r
878             }\r
879         }\r
880 \r
881         int dragDirection = 0;\r
882 \r
883         if (y > oldSeq)\r
884         {\r
885             dragDirection = 1;\r
886         }\r
887         else if (y < oldSeq)\r
888         {\r
889             dragDirection = -1;\r
890         }\r
891 \r
892         while ((y != oldSeq) && (oldSeq > 0) && (y < av.alignment.getHeight()))\r
893         {\r
894             // This routine ensures we don't skip any sequences, as the\r
895             // selection is quite slow.\r
896             Sequence seq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);\r
897 \r
898             oldSeq += dragDirection;\r
899 \r
900             Sequence nextSeq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);\r
901 \r
902             if (stretchGroup.sequences.contains(nextSeq))\r
903             {\r
904                 stretchGroup.deleteSequence(seq, false);\r
905             }\r
906             else\r
907             {\r
908                 if (seq != null)\r
909                 {\r
910                     stretchGroup.addSequence(seq, false);\r
911                 }\r
912 \r
913                 stretchGroup.addSequence(nextSeq, false);\r
914             }\r
915         }\r
916 \r
917         oldSeq = y;\r
918         mouseDragging = true;\r
919 \r
920         if (scrollThread != null)\r
921         {\r
922             scrollThread.setEvent(evt);\r
923         }\r
924 \r
925         seqCanvas.repaint();\r
926     }\r
927 \r
928     /**\r
929      * DOCUMENT ME!\r
930      *\r
931      * @param e DOCUMENT ME!\r
932      */\r
933     public void doMouseEnteredDefineMode(MouseEvent e)\r
934     {\r
935         if (scrollThread != null)\r
936         {\r
937             scrollThread.running = false;\r
938         }\r
939     }\r
940 \r
941     /**\r
942      * DOCUMENT ME!\r
943      *\r
944      * @param e DOCUMENT ME!\r
945      */\r
946     public void doMouseExitedDefineMode(MouseEvent e)\r
947     {\r
948         if (av.getWrapAlignment())\r
949         {\r
950             return;\r
951         }\r
952 \r
953         if (mouseDragging)\r
954         {\r
955             scrollThread = new ScrollThread();\r
956         }\r
957     }\r
958 \r
959     // this class allows scrolling off the bottom of the visible alignment\r
960     class ScrollThread extends Thread\r
961     {\r
962         MouseEvent evt;\r
963         boolean running = false;\r
964 \r
965         public ScrollThread()\r
966         {\r
967             start();\r
968         }\r
969 \r
970         public void setEvent(MouseEvent e)\r
971         {\r
972             evt = e;\r
973         }\r
974 \r
975         public void stopScrolling()\r
976         {\r
977             running = false;\r
978         }\r
979 \r
980         public void run()\r
981         {\r
982             running = true;\r
983 \r
984             while (running)\r
985             {\r
986                 if (evt != null)\r
987                 {\r
988                     if (mouseDragging && (evt.getY() < 0) &&\r
989                             (av.getStartSeq() > 0))\r
990                     {\r
991                         running = ap.scrollUp(true);\r
992                     }\r
993 \r
994                     if (mouseDragging && (evt.getY() >= getHeight()) &&\r
995                             (av.alignment.getHeight() > av.getEndSeq()))\r
996                     {\r
997                         running = ap.scrollUp(false);\r
998                     }\r
999 \r
1000                     if (mouseDragging && (evt.getX() < 0))\r
1001                     {\r
1002                         running = ap.scrollRight(true);\r
1003                     }\r
1004                     else if (mouseDragging && (evt.getX() >= getWidth()))\r
1005                     {\r
1006                         running = ap.scrollRight(false);\r
1007                     }\r
1008                 }\r
1009 \r
1010                 try\r
1011                 {\r
1012                     Thread.sleep(20);\r
1013                 }\r
1014                 catch (Exception ex)\r
1015                 {\r
1016                 }\r
1017             }\r
1018         }\r
1019     }\r
1020 }\r