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