Merge branch 'releases/Release_2_11_3_Branch'
[jalview.git] / 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         StringBuffer text = new StringBuffer("Sequence " + (seq + 1) + " ID: " +\r
361                 sequence.getName());\r
362 \r
363         Object obj = null;\r
364         if (av.alignment.isNucleotide())\r
365         {\r
366           obj = ResidueProperties.nucleotideName.get(sequence.getCharAt(res) +\r
367               "");\r
368           if(obj!=null)\r
369             text.append(" Nucleotide: ");\r
370         }\r
371         else\r
372         {\r
373           obj = ResidueProperties.aa2Triplet.get(sequence.getCharAt(res) + "");\r
374           if(obj!=null)\r
375             text.append("  Residue: ");\r
376         }\r
377 \r
378         if (obj != null)\r
379         {\r
380 \r
381           if (obj != "")\r
382           {\r
383             text.append( obj + " (" +\r
384                         av.getAlignment().getSequenceAt(seq).findPosition(res) + ")");\r
385           }\r
386         }\r
387 \r
388         ap.alignFrame.statusBar.setText(text.toString());\r
389 \r
390         // use aa to see if the mouse pointer is on a\r
391         if (av.showSequenceFeatures)\r
392         {\r
393             Vector features = sequence.getDatasetSequence().getSequenceFeatures();\r
394             if(features!=null)\r
395             {\r
396               StringBuffer sbuffer = new StringBuffer("<html>");\r
397 \r
398               for (int i = 0; i < features.size(); i++)\r
399               {\r
400                 SequenceFeature sf = (SequenceFeature) features.elementAt(i);\r
401 \r
402                 if ( (sf.getBegin() <= sequence.findPosition(res)) &&\r
403                     (sf.getEnd() >= sequence.findPosition(res)))\r
404                 {\r
405                   if (sf.getType().equals("disulfide bond"))\r
406                   {\r
407                     if (sf.getBegin() == sequence.findPosition(res)\r
408                         || sf.getEnd() == sequence.findPosition(res))\r
409                     {\r
410                       if (sbuffer.length() > 6)\r
411                         sbuffer.append("<br>");\r
412                       sbuffer.append("disulfide bond " + sf.getBegin() + ":" +\r
413                                      sf.getEnd());\r
414                     }\r
415                   }\r
416                   else\r
417                   {\r
418                     if (sbuffer.length() > 6)\r
419                       sbuffer.append("<br>");\r
420                     sbuffer.append(sf.getType());\r
421                     if (sf.getDescription() != null)\r
422                       sbuffer.append(" " + sf.getDescription());\r
423 \r
424                     if (sf.getStatus() != null)\r
425                     {\r
426                       sbuffer.append(" (" + sf.getStatus() + ")");\r
427                     }\r
428                   }\r
429                 }\r
430 \r
431               }\r
432 \r
433               sbuffer.append("</html>");\r
434               if(sbuffer.length()==13) // <html></html>\r
435                 setToolTipText("");\r
436               else\r
437                setToolTipText(sbuffer.toString());\r
438             }\r
439             else\r
440               setToolTipText("");\r
441         }\r
442     }\r
443 \r
444     /**\r
445      * DOCUMENT ME!\r
446      *\r
447      * @param evt DOCUMENT ME!\r
448      */\r
449     public void doMouseDragged(MouseEvent evt)\r
450     {\r
451         // If we're dragging we're editing\r
452         int res = findRes(evt);\r
453 \r
454         if (res < 0)\r
455         {\r
456             res = 0;\r
457         }\r
458 \r
459         if ((lastres == -1) || (lastres == res))\r
460         {\r
461             return;\r
462         }\r
463 \r
464         boolean dragRight = true;\r
465 \r
466         if ((res < av.getAlignment().getWidth()) && (res < lastres))\r
467         {\r
468             dragRight = false;\r
469         }\r
470 \r
471         if (res != lastres)\r
472         {\r
473             // Group editing\r
474             if (groupEditing)\r
475             {\r
476                 SequenceGroup sg = av.getSelectionGroup();\r
477 \r
478                 if (sg == null)\r
479                 {\r
480                     lastres = -1;\r
481 \r
482                     return;\r
483                 }\r
484 \r
485                 // drag to right\r
486                 if (dragRight)\r
487                 {\r
488                     sg.setEndRes(sg.getEndRes() + (res - lastres));\r
489                 }\r
490 \r
491                 // drag to left\r
492                 else\r
493                 {\r
494                     /// Are we able to delete?\r
495                     // ie are all columns blank?\r
496                     boolean deleteAllowed = false;\r
497 \r
498                     for (int s = 0; s < sg.getSize(); s++)\r
499                     {\r
500                         SequenceI seq = sg.getSequenceAt(s);\r
501 \r
502                         for (int j = res; j < lastres; j++)\r
503                         {\r
504                             if (seq.getSequence().length() <= j)\r
505                             {\r
506                                 continue;\r
507                             }\r
508 \r
509                             if (!jalview.util.Comparison.isGap(\r
510                                         seq.getSequence().charAt(j)))\r
511                             {\r
512                                 // Not a gap, block edit not valid\r
513                                 res = j + 1;\r
514                                 deleteAllowed = false;\r
515 \r
516                                 continue;\r
517                             }\r
518 \r
519                             deleteAllowed = true;\r
520                         }\r
521                     }\r
522 \r
523                     if (!deleteAllowed)\r
524                     {\r
525                         lastres = -1;\r
526 \r
527                         return;\r
528                     }\r
529 \r
530                     sg.setEndRes(sg.getEndRes() - (lastres - res));\r
531                 }\r
532 \r
533                 for (int i = 0; i < sg.getSize(); i++)\r
534                 {\r
535                     SequenceI s = sg.getSequenceAt(i);\r
536                     int k = av.alignment.findIndex(s);\r
537 \r
538                     // drag to right\r
539                     if (dragRight)\r
540                     {\r
541                         for (int j = lastres; j < res; j++)\r
542                         {\r
543                             insertChar(j, k);\r
544                         }\r
545                     }\r
546 \r
547                     // drag to left\r
548                     else\r
549                     {\r
550                         for (int j = res; j < lastres; j++)\r
551                         {\r
552                             if (s.getLength() > j)\r
553                             {\r
554                                 deleteChar(res, k);\r
555                             }\r
556                         }\r
557                     }\r
558                 }\r
559             }\r
560             else /////Editing a single sequence///////////\r
561             {\r
562                 if ((res < av.getAlignment().getWidth()) && (res > lastres))\r
563                 {\r
564                     // dragging to the right\r
565                     for (int j = lastres; j < res; j++)\r
566                     {\r
567                         insertChar(j, startseq);\r
568                     }\r
569                 }\r
570                 else if ((res < av.getAlignment().getWidth()) &&\r
571                         (res < lastres))\r
572                 {\r
573                     // dragging to the left\r
574                     for (int j = lastres; j > res; j--)\r
575                     {\r
576                         if (jalview.util.Comparison.isGap(\r
577                                     av.alignment.getSequenceAt(startseq)\r
578                                                     .getSequence().charAt(res)))\r
579                         {\r
580                             deleteChar(res, startseq);\r
581                         }\r
582                         else\r
583                         {\r
584                             break;\r
585                         }\r
586                     }\r
587                 }\r
588             }\r
589         }\r
590 \r
591         endEdit = res;\r
592         lastres = res;\r
593         seqCanvas.repaint();\r
594     }\r
595 \r
596     /**\r
597      * DOCUMENT ME!\r
598      *\r
599      * @param seqstart DOCUMENT ME!\r
600      * @param seqend DOCUMENT ME!\r
601      * @param start DOCUMENT ME!\r
602      */\r
603     public void drawChars(int seqstart, int seqend, int start)\r
604     {\r
605         seqCanvas.drawPanel(seqCanvas.gg, start, av.getEndRes(), seqstart,\r
606             seqend, av.getStartRes(), av.getStartSeq(), 0);\r
607         seqCanvas.repaint();\r
608     }\r
609 \r
610     /**\r
611      * DOCUMENT ME!\r
612      *\r
613      * @param j DOCUMENT ME!\r
614      * @param seq DOCUMENT ME!\r
615      */\r
616     public void insertChar(int j, int seq)\r
617     {\r
618         av.alignment.getSequenceAt(seq).insertCharAt(j, av.getGapCharacter());\r
619         seqEditOccurred = seq;\r
620     }\r
621 \r
622     /**\r
623      * DOCUMENT ME!\r
624      *\r
625      * @param j DOCUMENT ME!\r
626      * @param seq DOCUMENT ME!\r
627      */\r
628     public void deleteChar(int j, int seq)\r
629     {\r
630         av.alignment.getSequenceAt(seq).deleteCharAt(j);\r
631         seqEditOccurred = seq;\r
632 \r
633         av.alignment.getWidth();\r
634         seqCanvas.repaint();\r
635     }\r
636 \r
637     /**\r
638      * DOCUMENT ME!\r
639      *\r
640      * @param i DOCUMENT ME!\r
641      */\r
642     void editOccurred(int i)\r
643     {\r
644       if (endEdit == startEdit)\r
645       {\r
646         ap.alignFrame.historyList.pop();\r
647         ap.alignFrame.updateEditMenuBar();\r
648       }\r
649 \r
650       av.firePropertyChange("alignment", null,av.getAlignment().getSequences());\r
651 \r
652     }\r
653 \r
654     /**\r
655      * DOCUMENT ME!\r
656      *\r
657      * @param evt DOCUMENT ME!\r
658      */\r
659     public void doMousePressedDefineMode(MouseEvent evt)\r
660     {\r
661       int res = findRes(evt);\r
662       int seq = findSeq(evt);\r
663       oldSeq = seq;\r
664 \r
665       startWrapBlock=wrappedBlock;\r
666 \r
667       if(av.wrapAlignment && seq>av.alignment.getHeight())\r
668       {\r
669           JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
670               "Cannot edit annotations in wrapped view.",\r
671               "Wrapped view - no edit",\r
672               JOptionPane.WARNING_MESSAGE);\r
673         return;\r
674       }\r
675 \r
676       if(seq<0 || res<0)\r
677             return;\r
678 \r
679 \r
680         SequenceI sequence = (Sequence) av.getAlignment().getSequenceAt(seq);\r
681 \r
682         if ((sequence == null) || (res > sequence.getLength()))\r
683         {\r
684             return;\r
685         }\r
686 \r
687         stretchGroup = av.getSelectionGroup();\r
688 \r
689         if (stretchGroup == null)\r
690         {\r
691             stretchGroup = av.alignment.findGroup(sequence);\r
692 \r
693             if ((stretchGroup != null) && (res > stretchGroup.getStartRes()) &&\r
694                     (res < stretchGroup.getEndRes()))\r
695             {\r
696                 av.setSelectionGroup(stretchGroup);\r
697             }\r
698             else\r
699             {\r
700                 stretchGroup = null;\r
701             }\r
702         }\r
703         else if (!stretchGroup.sequences.contains(sequence) ||\r
704                 (stretchGroup.getStartRes() > res) ||\r
705                 (stretchGroup.getEndRes() < res))\r
706         {\r
707             stretchGroup = null;\r
708 \r
709             SequenceGroup[] allGroups = av.alignment.findAllGroups(sequence);\r
710 \r
711             if (allGroups != null)\r
712             {\r
713                 for (int i = 0; i < allGroups.length; i++)\r
714                 {\r
715                     if ((allGroups[i].getStartRes() <= res) &&\r
716                             (allGroups[i].getEndRes() >= res))\r
717                     {\r
718                         stretchGroup = allGroups[i];\r
719                         av.setSelectionGroup(stretchGroup);\r
720 \r
721                         break;\r
722                     }\r
723                 }\r
724             }\r
725         }\r
726 \r
727         if (stretchGroup == null)\r
728         {\r
729             // define a new group here\r
730             SequenceGroup sg = new SequenceGroup();\r
731             sg.setStartRes(res);\r
732             sg.setEndRes(res);\r
733             sg.addSequence(sequence, false);\r
734             av.setSelectionGroup(sg);\r
735             stretchGroup = sg;\r
736 \r
737             if (av.getConservationSelected())\r
738             {\r
739                 SliderPanel.setConservationSlider(ap,\r
740                     av.getGlobalColourScheme(), "Background");\r
741             }\r
742 \r
743             if (av.getAbovePIDThreshold())\r
744             {\r
745                 SliderPanel.setPIDSliderSource(ap, av.getGlobalColourScheme(),\r
746                     "Background");\r
747             }\r
748         }\r
749         else if (javax.swing.SwingUtilities.isRightMouseButton(evt))\r
750         {\r
751             jalview.gui.PopupMenu pop = new jalview.gui.PopupMenu(ap, null);\r
752             pop.show(this, evt.getX(), evt.getY());\r
753 \r
754             // edit the properties of existing group\r
755         }\r
756 \r
757         if ((stretchGroup != null) && (stretchGroup.getEndRes() == res))\r
758         {\r
759             // Edit end res position of selected group\r
760             changeEndRes = true;\r
761         }\r
762         else if ((stretchGroup != null) && (stretchGroup.getStartRes() == res))\r
763         {\r
764             // Edit end res position of selected group\r
765             changeStartRes = true;\r
766         }\r
767 \r
768         stretchGroup.getWidth();\r
769 \r
770         seqCanvas.repaint();\r
771     }\r
772 \r
773     /**\r
774      * DOCUMENT ME!\r
775      *\r
776      * @param evt DOCUMENT ME!\r
777      */\r
778     public void doMouseReleasedDefineMode(MouseEvent evt)\r
779     {\r
780         if (mouseDragging)\r
781         {\r
782             stretchGroup.recalcConservation();\r
783             mouseDragging = false;\r
784         }\r
785 \r
786         if (stretchGroup == null)\r
787         {\r
788             return;\r
789         }\r
790 \r
791         if(stretchGroup.cs!=null)\r
792         {\r
793           if (stretchGroup.cs instanceof ClustalxColourScheme)\r
794           {\r
795             ( (ClustalxColourScheme) stretchGroup.cs).resetClustalX(stretchGroup.\r
796                 sequences,\r
797                 stretchGroup.getWidth());\r
798           }\r
799 \r
800           if (stretchGroup.cs.conservationApplied())\r
801           {\r
802             SliderPanel.setConservationSlider(ap, stretchGroup.cs,\r
803                                               stretchGroup.getName());\r
804           }\r
805           else\r
806           {\r
807             SliderPanel.setPIDSliderSource(ap, stretchGroup.cs,\r
808                                            stretchGroup.getName());\r
809           }\r
810         }\r
811         changeEndRes = false;\r
812         changeStartRes = false;\r
813         stretchGroup = null;\r
814         PaintRefresher.Refresh(av.alignment);\r
815     }\r
816 \r
817     /**\r
818      * DOCUMENT ME!\r
819      *\r
820      * @param evt DOCUMENT ME!\r
821      */\r
822     public void doMouseDraggedDefineMode(MouseEvent evt)\r
823     {\r
824       int res = findRes(evt);\r
825       int y = findSeq(evt);\r
826 \r
827       if(wrappedBlock!=startWrapBlock)\r
828         return;\r
829 \r
830       if (stretchGroup == null)\r
831       {\r
832             return;\r
833         }\r
834 \r
835         if (res > av.alignment.getWidth())\r
836         {\r
837             res = av.alignment.getWidth() - 1;\r
838         }\r
839 \r
840         if (stretchGroup.getEndRes() == res)\r
841         {\r
842             // Edit end res position of selected group\r
843             changeEndRes = true;\r
844         }\r
845         else if (stretchGroup.getStartRes() == res)\r
846         {\r
847             // Edit start res position of selected group\r
848             changeStartRes = true;\r
849         }\r
850 \r
851         if (res < av.getStartRes())\r
852         {\r
853             res = av.getStartRes();\r
854         }\r
855         else if (res > av.getEndRes() && !av.getWrapAlignment())\r
856         {\r
857             res = av.getEndRes();\r
858         }\r
859 \r
860         if (changeEndRes)\r
861         {\r
862             if (res > (stretchGroup.getStartRes() - 1))\r
863             {\r
864                 stretchGroup.setEndRes(res);\r
865             }\r
866         }\r
867         else if (changeStartRes)\r
868         {\r
869             if (res < (stretchGroup.getEndRes() + 1))\r
870             {\r
871                 stretchGroup.setStartRes(res);\r
872             }\r
873         }\r
874 \r
875         int dragDirection = 0;\r
876 \r
877         if (y > oldSeq)\r
878         {\r
879             dragDirection = 1;\r
880         }\r
881         else if (y < oldSeq)\r
882         {\r
883             dragDirection = -1;\r
884         }\r
885 \r
886         while ((y != oldSeq) && (oldSeq > 0) && (y < av.alignment.getHeight()))\r
887         {\r
888             // This routine ensures we don't skip any sequences, as the\r
889             // selection is quite slow.\r
890             Sequence seq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);\r
891 \r
892             oldSeq += dragDirection;\r
893 \r
894             Sequence nextSeq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);\r
895 \r
896             if (stretchGroup.sequences.contains(nextSeq))\r
897             {\r
898                 stretchGroup.deleteSequence(seq, false);\r
899             }\r
900             else\r
901             {\r
902                 if (seq != null)\r
903                 {\r
904                     stretchGroup.addSequence(seq, false);\r
905                 }\r
906 \r
907                 stretchGroup.addSequence(nextSeq, false);\r
908             }\r
909         }\r
910 \r
911         oldSeq = y;\r
912         mouseDragging = true;\r
913 \r
914         if (scrollThread != null)\r
915         {\r
916             scrollThread.setEvent(evt);\r
917         }\r
918 \r
919         seqCanvas.repaint();\r
920     }\r
921 \r
922     /**\r
923      * DOCUMENT ME!\r
924      *\r
925      * @param e DOCUMENT ME!\r
926      */\r
927     public void doMouseEnteredDefineMode(MouseEvent e)\r
928     {\r
929         if (scrollThread != null)\r
930         {\r
931             scrollThread.running = false;\r
932         }\r
933     }\r
934 \r
935     /**\r
936      * DOCUMENT ME!\r
937      *\r
938      * @param e DOCUMENT ME!\r
939      */\r
940     public void doMouseExitedDefineMode(MouseEvent e)\r
941     {\r
942         if (av.getWrapAlignment())\r
943         {\r
944             return;\r
945         }\r
946 \r
947         if (mouseDragging)\r
948         {\r
949             scrollThread = new ScrollThread();\r
950         }\r
951     }\r
952 \r
953     // this class allows scrolling off the bottom of the visible alignment\r
954     class ScrollThread extends Thread\r
955     {\r
956         MouseEvent evt;\r
957         boolean running = false;\r
958 \r
959         public ScrollThread()\r
960         {\r
961             start();\r
962         }\r
963 \r
964         public void setEvent(MouseEvent e)\r
965         {\r
966             evt = e;\r
967         }\r
968 \r
969         public void stopScrolling()\r
970         {\r
971             running = false;\r
972         }\r
973 \r
974         public void run()\r
975         {\r
976             running = true;\r
977 \r
978             while (running)\r
979             {\r
980                 if (evt != null)\r
981                 {\r
982                     if (mouseDragging && (evt.getY() < 0) &&\r
983                             (av.getStartSeq() > 0))\r
984                     {\r
985                         running = ap.scrollUp(true);\r
986                     }\r
987 \r
988                     if (mouseDragging && (evt.getY() >= getHeight()) &&\r
989                             (av.alignment.getHeight() > av.getEndSeq()))\r
990                     {\r
991                         running = ap.scrollUp(false);\r
992                     }\r
993 \r
994                     if (mouseDragging && (evt.getX() < 0))\r
995                     {\r
996                         running = ap.scrollRight(true);\r
997                     }\r
998                     else if (mouseDragging && (evt.getX() >= getWidth()))\r
999                     {\r
1000                         running = ap.scrollRight(false);\r
1001                     }\r
1002                 }\r
1003 \r
1004                 try\r
1005                 {\r
1006                     Thread.sleep(75);\r
1007                 }\r
1008                 catch (Exception ex)\r
1009                 {\r
1010                 }\r
1011             }\r
1012         }\r
1013     }\r
1014 }\r