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