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