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