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