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