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