catch control down before editing null pointer
[jalview.git] / src / jalview / appletgui / SeqPanel.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2006 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.awt.*;\r
23 import java.awt.event.*;\r
24 \r
25 import jalview.datamodel.*;\r
26 import jalview.schemes.*;\r
27 import jalview.commands.*;\r
28 \r
29 import java.util.Vector;\r
30 \r
31 public class SeqPanel\r
32     extends Panel implements MouseMotionListener, MouseListener\r
33 {\r
34 \r
35   public SeqCanvas seqCanvas;\r
36   public AlignmentPanel ap;\r
37 \r
38   protected int lastres;\r
39   protected int startseq;\r
40 \r
41   protected AlignViewport av;\r
42 \r
43   // if character is inserted or deleted, we will need to recalculate the conservation\r
44   boolean seqEditOccurred = false;\r
45 \r
46   ScrollThread scrollThread = null;\r
47   boolean mouseDragging = false;\r
48   boolean editingSeqs = false;\r
49   boolean groupEditing = false;\r
50 \r
51   int oldSeq = -1;\r
52   boolean changeEndSeq = false;\r
53   boolean changeStartSeq = false;\r
54   boolean changeEndRes = false;\r
55   boolean changeStartRes = false;\r
56   SequenceGroup stretchGroup = null;\r
57 \r
58   StringBuffer keyboardNo1;\r
59   StringBuffer keyboardNo2;\r
60 \r
61   boolean mouseWheelPressed = false;\r
62   Point lastMousePress;\r
63 \r
64   EditCommand editCommand;\r
65 \r
66   public SeqPanel(AlignViewport avp, AlignmentPanel p)\r
67   {\r
68     this.av = avp;\r
69 \r
70     seqCanvas = new SeqCanvas(avp);\r
71     setLayout(new BorderLayout());\r
72     add(seqCanvas);\r
73 \r
74     ap = p;\r
75 \r
76     seqCanvas.addMouseMotionListener(this);\r
77     seqCanvas.addMouseListener(this);\r
78 \r
79     seqCanvas.repaint();\r
80   }\r
81 \r
82   void endEditing()\r
83   {\r
84     if (editCommand!=null && editCommand.getSize() > 0)\r
85     {\r
86       ap.alignFrame.addHistoryItem(editCommand);\r
87       av.firePropertyChange("alignment", null,\r
88                             av.getAlignment().getSequences());\r
89     }\r
90 \r
91     startseq = -1;\r
92     lastres = -1;\r
93     editingSeqs = false;\r
94     groupEditing = false;\r
95     keyboardNo1 = null;\r
96     keyboardNo2 = null;\r
97      editCommand = null;\r
98    }\r
99 \r
100    void setCursorRow()\r
101    {\r
102      seqCanvas.cursorY = getKeyboardNo(keyboardNo1)-1;\r
103      scrollToVisible();\r
104    }\r
105 \r
106    void setCursorColumn()\r
107    {\r
108      seqCanvas.cursorX = getKeyboardNo(keyboardNo1)-1;\r
109      scrollToVisible();\r
110    }\r
111 \r
112    void setCursorRowAndColumn()\r
113    {\r
114      if(keyboardNo2==null)\r
115      {\r
116        keyboardNo2 = new StringBuffer();\r
117      }\r
118      else\r
119      {\r
120        seqCanvas.cursorX = getKeyboardNo(keyboardNo1) - 1;\r
121        seqCanvas.cursorY = getKeyboardNo(keyboardNo2) - 1;\r
122        scrollToVisible();\r
123      }\r
124    }\r
125 \r
126    void setCursorPosition()\r
127    {\r
128      SequenceI sequence =\r
129          (Sequence) av.getAlignment().getSequenceAt(seqCanvas.cursorY);\r
130 \r
131      seqCanvas.cursorX = sequence.findIndex(\r
132          getKeyboardNo(keyboardNo1)-1\r
133          );\r
134      scrollToVisible();\r
135    }\r
136 \r
137    void moveCursor(int dx, int dy)\r
138    {\r
139      seqCanvas.cursorX += dx;\r
140      seqCanvas.cursorY += dy;\r
141      if (av.hasHiddenColumns && !av.colSel.isVisible(seqCanvas.cursorX))\r
142      {\r
143        int original = seqCanvas.cursorX - dx;\r
144        int maxWidth = av.alignment.getWidth();\r
145 \r
146        while(!av.colSel.isVisible(seqCanvas.cursorX)\r
147              && seqCanvas.cursorX<maxWidth\r
148              && seqCanvas.cursorX>0)\r
149        {\r
150          seqCanvas.cursorX += dx;\r
151        }\r
152 \r
153        if(seqCanvas.cursorX>=maxWidth\r
154           || !av.colSel.isVisible(seqCanvas.cursorX) )\r
155        {\r
156          seqCanvas.cursorX = original;\r
157        }\r
158       }\r
159      scrollToVisible();\r
160    }\r
161 \r
162    void scrollToVisible()\r
163    {\r
164      if (seqCanvas.cursorX < 0)\r
165        seqCanvas.cursorX = 0;\r
166      else if (seqCanvas.cursorX > av.alignment.getWidth() - 1)\r
167        seqCanvas.cursorX = av.alignment.getWidth() - 1;\r
168 \r
169      if (seqCanvas.cursorY < 0)\r
170        seqCanvas.cursorY = 0;\r
171      else if (seqCanvas.cursorY > av.alignment.getHeight() - 1)\r
172        seqCanvas.cursorY = av.alignment.getHeight() - 1;\r
173 \r
174 \r
175      endEditing();\r
176      if (av.wrapAlignment)\r
177      {\r
178        ap.scrollToWrappedVisible(seqCanvas.cursorX);\r
179      }\r
180      else\r
181      {\r
182        while (seqCanvas.cursorY < av.startSeq)\r
183        {\r
184          ap.scrollUp(true);\r
185        }\r
186        while (seqCanvas.cursorY + 1 > av.endSeq)\r
187        {\r
188          ap.scrollUp(false);\r
189        }\r
190        while (seqCanvas.cursorX < av.colSel.adjustForHiddenColumns(av.startRes))\r
191        {\r
192 \r
193          if (!ap.scrollRight(false))\r
194            break;\r
195        }\r
196        while (seqCanvas.cursorX > av.colSel.adjustForHiddenColumns(av.endRes))\r
197        {\r
198          if (!ap.scrollRight(true))\r
199            break;\r
200        }\r
201      }\r
202      setStatusMessage(av.alignment.getSequenceAt(seqCanvas.cursorY),\r
203                       seqCanvas.cursorX, seqCanvas.cursorY);\r
204 \r
205      seqCanvas.repaint();\r
206    }\r
207 \r
208    void setSelectionAreaAtCursor(boolean topLeft)\r
209    {\r
210      SequenceI sequence =\r
211          (Sequence) av.getAlignment().getSequenceAt(seqCanvas.cursorY);\r
212 \r
213      if(av.getSelectionGroup()!=null)\r
214      {\r
215        SequenceGroup sg = av.selectionGroup;\r
216        //Find the top and bottom of this group\r
217        int min = av.alignment.getHeight(), max = 0;\r
218        for(int i=0; i<sg.getSize(); i++)\r
219        {\r
220          int index = av.alignment.findIndex( sg.getSequenceAt(i) );\r
221          if(index > max)\r
222            max = index;\r
223          if(index < min)\r
224            min = index;\r
225        }\r
226 \r
227        max ++;\r
228 \r
229        if(topLeft)\r
230        {\r
231          sg.setStartRes(seqCanvas.cursorX);\r
232          if(sg.getEndRes()<seqCanvas.cursorX)\r
233            sg.setEndRes(seqCanvas.cursorX);\r
234 \r
235          min = seqCanvas.cursorY;\r
236        }\r
237        else\r
238        {\r
239          sg.setEndRes(seqCanvas.cursorX);\r
240          if(sg.getStartRes()>seqCanvas.cursorX)\r
241            sg.setStartRes(seqCanvas.cursorX);\r
242 \r
243          max = seqCanvas.cursorY+1;\r
244        }\r
245 \r
246        if(min>max)\r
247        {\r
248          // Only the user can do this\r
249          av.setSelectionGroup(null);\r
250        }\r
251        else\r
252        {\r
253          // Now add any sequences between min and max\r
254          sg.getSequences(null).removeAllElements();\r
255          for (int i = min; i < max; i++)\r
256          {\r
257            sg.addSequence(av.alignment.getSequenceAt(i), false);\r
258          }\r
259        }\r
260      }\r
261 \r
262      if (av.getSelectionGroup() == null)\r
263      {\r
264        SequenceGroup sg = new SequenceGroup();\r
265        sg.setStartRes(seqCanvas.cursorX);\r
266        sg.setEndRes(seqCanvas.cursorX);\r
267        sg.addSequence(sequence, false);\r
268        av.setSelectionGroup(sg);\r
269      }\r
270 \r
271 \r
272      ap.repaint();\r
273    }\r
274 \r
275    void insertGapAtCursor(boolean group)\r
276    {\r
277      groupEditing = group;\r
278      startseq = seqCanvas.cursorY;\r
279      lastres = seqCanvas.cursorX;\r
280      editSequence(true, seqCanvas.cursorX+getKeyboardNo(keyboardNo1));\r
281      endEditing();\r
282    }\r
283 \r
284    void deleteGapAtCursor(boolean group)\r
285    {\r
286      groupEditing = group;\r
287      startseq = seqCanvas.cursorY;\r
288      lastres = seqCanvas.cursorX+getKeyboardNo(keyboardNo1);\r
289      editSequence(false, seqCanvas.cursorX);\r
290      endEditing();\r
291    }\r
292 \r
293    void numberPressed(char value)\r
294    {\r
295      if(keyboardNo1==null)\r
296        keyboardNo1 = new StringBuffer();\r
297 \r
298      if(keyboardNo2!=null)\r
299        keyboardNo2.append(value);\r
300      else\r
301        keyboardNo1.append(value);\r
302    }\r
303 \r
304    int getKeyboardNo(StringBuffer kb)\r
305    {\r
306      if(kb==null)\r
307        return 1;\r
308      else\r
309        return Integer.parseInt(kb.toString());\r
310    }\r
311 \r
312    void setStatusMessage(SequenceI sequence, int res, int seq)\r
313    {\r
314      StringBuffer text = new StringBuffer("Sequence " + (seq + 1) + " ID: " +\r
315                                           sequence.getName());\r
316 \r
317      Object obj = null;\r
318      if (av.alignment.isNucleotide())\r
319      {\r
320        obj = ResidueProperties.nucleotideName.get(sequence.getCharAt(res) +\r
321                                                   "");\r
322        if (obj != null)\r
323          text.append(" Nucleotide: ");\r
324      }\r
325      else\r
326      {\r
327        obj = ResidueProperties.aa2Triplet.get(sequence.getCharAt(res) + "");\r
328        if (obj != null)\r
329          text.append("  Residue: ");\r
330      }\r
331 \r
332      if (obj != null)\r
333      {\r
334 \r
335        if (obj != "")\r
336        {\r
337          text.append(obj + " (" + sequence.findPosition(res) +\r
338                      ")");\r
339        }\r
340      }\r
341 \r
342      ap.alignFrame.statusBar.setText(text.toString());\r
343 \r
344     }\r
345      public void mousePressed(MouseEvent evt)\r
346      {\r
347        lastMousePress = evt.getPoint();\r
348 \r
349        //For now, ignore the mouseWheel font resizing on Macs\r
350        //As the Button2_mask always seems to be true\r
351        if ( (evt.getModifiers() & InputEvent.BUTTON2_MASK) ==\r
352          InputEvent.BUTTON2_MASK && !av.MAC)\r
353        {\r
354          mouseWheelPressed = true;\r
355          return;\r
356        }\r
357 \r
358        if (evt.isShiftDown()\r
359            || evt.isControlDown()\r
360            || evt.isAltDown())\r
361        {\r
362          if (evt.isControlDown() || evt.isAltDown())\r
363          {\r
364            groupEditing = true;\r
365          }\r
366          editingSeqs = true;\r
367        }\r
368        else\r
369        {\r
370          doMousePressedDefineMode(evt);\r
371          return;\r
372        }\r
373 \r
374 \r
375        int seq = findSeq(evt);\r
376        int res = findRes(evt);\r
377 \r
378        if(seq<0 || res<0)\r
379          return;\r
380 \r
381 \r
382          if ((seq < av.getAlignment().getHeight()) &&\r
383                  (res < av.getAlignment().getSequenceAt(seq).getLength()))\r
384          {\r
385              startseq = seq;\r
386              lastres = res;\r
387          }\r
388          else\r
389          {\r
390              startseq = -1;\r
391              lastres = -1;\r
392          }\r
393 \r
394         return;\r
395      }\r
396 \r
397      public void mouseClicked(MouseEvent evt){}\r
398 \r
399 \r
400   public void mouseReleased(MouseEvent evt)\r
401   {\r
402     mouseDragging = false;\r
403     mouseWheelPressed = false;\r
404 \r
405     if (!editingSeqs)\r
406     {\r
407        doMouseReleasedDefineMode(evt);\r
408        return;\r
409     }\r
410 \r
411      endEditing();\r
412      ap.repaint();\r
413   }\r
414 \r
415   int startWrapBlock=-1;\r
416   int wrappedBlock=-1;\r
417   int findRes(MouseEvent evt)\r
418  {\r
419    int res = 0;\r
420    int x = evt.getX();\r
421 \r
422   if (av.wrapAlignment)\r
423   {\r
424 \r
425     int hgap = av.charHeight;\r
426     if (av.scaleAboveWrapped)\r
427       hgap += av.charHeight;\r
428 \r
429     int cHeight = av.getAlignment().getHeight() * av.charHeight\r
430         + hgap + seqCanvas.getAnnotationHeight();\r
431 \r
432       int y = evt.getY();\r
433       y -= hgap;\r
434       x -= seqCanvas.LABEL_WEST;\r
435 \r
436 \r
437       int cwidth = seqCanvas.getWrappedCanvasWidth(getSize().width);\r
438       if(cwidth<1)\r
439         return 0;\r
440 \r
441       wrappedBlock = y / cHeight;\r
442       wrappedBlock += av.getStartRes() / cwidth;\r
443 \r
444       res = wrappedBlock * cwidth + x / av.getCharWidth();\r
445 \r
446   }\r
447   else\r
448   {\r
449       res = (x / av.getCharWidth()) + av.getStartRes();\r
450   }\r
451 \r
452   if(av.hasHiddenColumns)\r
453           res = av.getColumnSelection().adjustForHiddenColumns(res);\r
454 \r
455   return res;\r
456 \r
457  }\r
458 \r
459  int findSeq(MouseEvent evt)\r
460  {\r
461 \r
462    int seq = 0;\r
463    int y = evt.getY();\r
464 \r
465    if (av.wrapAlignment)\r
466    {\r
467      int hgap = av.charHeight;\r
468      if (av.scaleAboveWrapped)\r
469        hgap += av.charHeight;\r
470 \r
471      int cHeight = av.getAlignment().getHeight() * av.charHeight\r
472          + hgap + seqCanvas.getAnnotationHeight();\r
473 \r
474        y -= hgap;\r
475 \r
476      seq = Math.min( (y % cHeight) / av.getCharHeight(),\r
477                      av.alignment.getHeight() -1);\r
478      if(seq<0)\r
479        seq = 0;\r
480    }\r
481    else\r
482    {\r
483      seq = Math.min( (y / av.getCharHeight()) + av.getStartSeq(),\r
484                      av.alignment.getHeight() -1);\r
485      if(seq<0)\r
486        seq = 0;\r
487    }\r
488 \r
489    return seq;\r
490  }\r
491 \r
492 \r
493   public void doMousePressed(MouseEvent evt)\r
494   {\r
495 \r
496     int seq = findSeq(evt);\r
497     int res = findRes(evt);\r
498 \r
499     if (seq < av.getAlignment().getHeight() &&\r
500         res < av.getAlignment().getSequenceAt(seq).getLength())\r
501     {\r
502       //char resstr = align.getSequenceAt(seq).getSequence().charAt(res);\r
503       // Find the residue's position in the sequence (res is the position\r
504       // in the alignment\r
505 \r
506       startseq = seq;\r
507       lastres = res;\r
508     }\r
509     else\r
510     {\r
511       startseq = -1;\r
512       lastres = -1;\r
513     }\r
514 \r
515     return;\r
516   }\r
517 \r
518   public void mouseMoved(MouseEvent evt)\r
519   {\r
520     int res = findRes(evt);\r
521     int seq = findSeq(evt);\r
522 \r
523     if (seq >= av.getAlignment().getHeight() || seq<0 || res<0)\r
524     {\r
525       if(tooltip!=null)\r
526         tooltip.setTip("");\r
527       return;\r
528     }\r
529 \r
530     SequenceI sequence = av.getAlignment().getSequenceAt(seq);\r
531     if (res > sequence.getLength())\r
532     {\r
533       if(tooltip!=null)\r
534         tooltip.setTip("");\r
535       return;\r
536     }\r
537 \r
538     StringBuffer text = new StringBuffer("Sequence " + (seq + 1) + " ID: " +\r
539             sequence.getName());\r
540 \r
541     Object obj = null;\r
542     if (av.alignment.isNucleotide())\r
543     {\r
544       obj = ResidueProperties.nucleotideName.get(sequence.getCharAt(res) +\r
545           "");\r
546       if(obj!=null)\r
547         text.append(" Nucleotide: ");\r
548     }\r
549     else\r
550     {\r
551       obj = ResidueProperties.aa2Triplet.get(sequence.getCharAt(res) + "");\r
552       if(obj!=null)\r
553         text.append("  Residue: ");\r
554     }\r
555 \r
556     if (obj != null)\r
557     {\r
558       if (obj != "")\r
559       {\r
560         text.append(obj + " (" + sequence.findPosition(res) + ")");\r
561       }\r
562     }\r
563 \r
564     if(seqCanvas.pdbCanvas!=null && sequence==seqCanvas.pdbCanvas.sequence)\r
565     {\r
566       seqCanvas.pdbCanvas.highlightRes(sequence.findPosition(res));\r
567     }\r
568 \r
569     ap.alignFrame.statusBar.setText(text.toString());\r
570 \r
571     StringBuffer tooltipText = new StringBuffer();\r
572     SequenceGroup []  groups = av.alignment.findAllGroups(sequence);\r
573     if(groups!=null)\r
574     {\r
575       for(int g=0; g<groups.length; g++)\r
576       {\r
577         if(groups[g].getStartRes()<=res && groups[g].getEndRes()>=res)\r
578         {\r
579           if (!groups[g].getName().startsWith("JTreeGroup") &&\r
580               !groups[g].getName().startsWith("JGroup"))\r
581             tooltipText.append(groups[g].getName() + " ");\r
582           if(groups[g].getDescription()!=null)\r
583             tooltipText.append(groups[g].getDescription());\r
584           tooltipText.append("\n");\r
585         }\r
586       }\r
587     }\r
588 \r
589     // use aa to see if the mouse pointer is on a\r
590     if (av.showSequenceFeatures\r
591         && sequence.getSequenceFeatures()!=null\r
592         && av.featuresDisplayed!=null)\r
593     {\r
594 \r
595       Vector allFeatures = getAllFeaturesAtRes(sequence, sequence.findPosition(res));\r
596 \r
597       int index = 0;\r
598       while (index < allFeatures.size())\r
599       {\r
600         SequenceFeature sf = (SequenceFeature) allFeatures.elementAt(index);\r
601 \r
602         tooltipText.append(sf.getType()+" "+sf.begin+":"+sf.end);\r
603 \r
604         if (sf.getDescription() != null)\r
605           tooltipText.append(" " + sf.getDescription());\r
606 \r
607         if (sf.getValue("status") != null )\r
608         {\r
609           String status = sf.getValue("status").toString();\r
610           if(status.length()>0)\r
611             tooltipText.append(" (" + sf.getValue("status") + ")");\r
612         }\r
613         tooltipText.append("\n");\r
614 \r
615         index++;\r
616       }\r
617     }\r
618 \r
619     if (tooltip == null)\r
620       tooltip = new Tooltip(tooltipText.toString(), seqCanvas);\r
621     else\r
622       tooltip.setTip(tooltipText.toString());\r
623   }\r
624 \r
625   Vector getAllFeaturesAtRes(SequenceI seq, int res)\r
626   {\r
627     Vector allFeatures = new Vector();\r
628     int index = 0;\r
629     if(seq.getSequenceFeatures()!=null)\r
630     {\r
631       while (index < seq.getSequenceFeatures().length)\r
632       {\r
633         SequenceFeature sf = seq.getSequenceFeatures()[index];\r
634         if (sf.getBegin() <= res &&\r
635             sf.getEnd() >= res)\r
636         {\r
637           if (av.featuresDisplayed.containsKey(sf.getType()))\r
638           {\r
639             allFeatures.addElement(sf);\r
640           }\r
641         }\r
642         index++;\r
643       }\r
644     }\r
645     return allFeatures;\r
646   }\r
647 \r
648   Tooltip tooltip;\r
649 \r
650   public void mouseDragged(MouseEvent evt)\r
651   {\r
652     if (mouseWheelPressed)\r
653     {\r
654       int oldWidth = av.charWidth;\r
655 \r
656       //Which is bigger, left-right or up-down?\r
657       if (Math.abs(evt.getY() - lastMousePress.y)\r
658           > Math.abs(evt.getX() - lastMousePress.x))\r
659       {\r
660         int fontSize = av.font.getSize();\r
661 \r
662         if (evt.getY() < lastMousePress.y && av.charHeight > 1)\r
663         {\r
664           fontSize--;\r
665         }\r
666         else if (evt.getY() > lastMousePress.y)\r
667         {\r
668           fontSize++;\r
669         }\r
670 \r
671 \r
672         if(fontSize<1)\r
673           fontSize = 1;\r
674 \r
675         av.setFont(new Font(av.font.getName(), av.font.getStyle(), fontSize));\r
676         av.charWidth = oldWidth;\r
677       }\r
678       else\r
679       {\r
680         if (evt.getX() < lastMousePress.x && av.charWidth > 1)\r
681         {\r
682           av.charWidth--;\r
683         }\r
684         else if (evt.getX() > lastMousePress.x)\r
685         {\r
686           av.charWidth++;\r
687         }\r
688 \r
689         if(av.charWidth<1)\r
690         {\r
691           av.charWidth = 1;\r
692         }\r
693       }\r
694 \r
695       ap.fontChanged();\r
696 \r
697       FontMetrics fm = getFontMetrics(av.getFont());\r
698       av.validCharWidth = fm.charWidth('M') <= av.charWidth;\r
699 \r
700       lastMousePress = evt.getPoint();\r
701 \r
702       ap.repaint();\r
703       ap.annotationPanel.image = null;\r
704       return;\r
705       }\r
706 \r
707       if (!editingSeqs)\r
708       {\r
709         doMouseDraggedDefineMode(evt);\r
710         return;\r
711       }\r
712 \r
713   int res = findRes(evt);\r
714 \r
715   if (res < 0)\r
716   {\r
717       res = 0;\r
718   }\r
719 \r
720   if ((lastres == -1) || (lastres == res))\r
721   {\r
722       return;\r
723   }\r
724 \r
725   if ( (res < av.getAlignment().getWidth()) && (res < lastres))\r
726   {\r
727     // dragLeft, delete gap\r
728     editSequence(false, res);\r
729   }\r
730   else\r
731     editSequence(true, res);\r
732 \r
733   mouseDragging = true;\r
734   if(scrollThread!=null)\r
735     scrollThread.setEvent(evt);\r
736 \r
737   }\r
738 \r
739   synchronized void editSequence(boolean insertGap, int startres)\r
740   {\r
741     int fixedLeft = -1;\r
742     int fixedRight = -1;\r
743     boolean fixedColumns = false;\r
744     SequenceGroup sg = av.getSelectionGroup();\r
745 \r
746     SequenceI seq = av.alignment.getSequenceAt(startseq);\r
747 \r
748       if (!groupEditing && av.hasHiddenRows)\r
749       {\r
750         if (av.hiddenRepSequences!=null\r
751             && av.hiddenRepSequences.containsKey(seq))\r
752         {\r
753           sg = (SequenceGroup)av.hiddenRepSequences.get(seq);\r
754           groupEditing = true;\r
755           }\r
756       }\r
757 \r
758       StringBuffer message = new StringBuffer();\r
759       if (groupEditing)\r
760       {\r
761         message.append("Edit group:");\r
762         if (editCommand == null)\r
763           editCommand = new EditCommand("Edit Group");\r
764       }\r
765       else\r
766        {\r
767          message.append("Edit sequence: " + seq.getName());\r
768          String label = seq.getName();\r
769          if(label.length()>10)\r
770            label = label.substring(0,10);\r
771          if(editCommand==null)\r
772            editCommand = new EditCommand("Edit "+label);\r
773        }\r
774 \r
775      if(insertGap)\r
776        message.append(" insert ");\r
777      else\r
778        message.append(" delete ");\r
779 \r
780      message.append(Math.abs(startres-lastres)+" gaps.");\r
781      ap.alignFrame.statusBar.setText(message.toString());\r
782 \r
783 \r
784       //Are we editing within a selection group?\r
785       if (groupEditing\r
786           || (sg != null && sg.getSequences(av.hiddenRepSequences).contains(seq)))\r
787       {\r
788         fixedColumns = true;\r
789 \r
790         //sg might be null as the user may only see 1 sequence,\r
791         //but the sequence represents a group\r
792         if (sg == null)\r
793         {\r
794           if (av.hiddenRepSequences == null\r
795               || !av.hiddenRepSequences.containsKey(seq))\r
796           {\r
797             endEditing();\r
798             return;\r
799           }\r
800 \r
801           sg = (SequenceGroup) av.hiddenRepSequences.get(seq);\r
802         }\r
803 \r
804         fixedLeft = sg.getStartRes();\r
805         fixedRight = sg.getEndRes();\r
806 \r
807         if (   (startres < fixedLeft && lastres >= fixedLeft)\r
808             || (startres >= fixedLeft && lastres < fixedLeft)\r
809             || (startres > fixedRight && lastres <=fixedRight)\r
810             || (startres <= fixedRight && lastres > fixedRight))\r
811         {\r
812           endEditing();\r
813           return;\r
814         }\r
815 \r
816         if (fixedLeft > startres)\r
817         {\r
818           fixedRight = fixedLeft - 1;\r
819           fixedLeft = 0;\r
820         }\r
821         else if (fixedRight < startres)\r
822         {\r
823           fixedLeft = fixedRight;\r
824           fixedRight = -1;\r
825         }\r
826       }\r
827 \r
828 \r
829       if(av.hasHiddenColumns )\r
830       {\r
831           fixedColumns = true;\r
832           int y1 = av.getColumnSelection().getHiddenBoundaryLeft(startres);\r
833           int y2 = av.getColumnSelection().getHiddenBoundaryRight(startres);\r
834 \r
835           if ( (insertGap && startres > y1 && lastres < y1)\r
836               || (!insertGap && startres < y2 && lastres > y2))\r
837           {\r
838             endEditing();\r
839             return;\r
840           }\r
841 \r
842           //System.out.print(y1+" "+y2+" "+fixedLeft+" "+fixedRight+"~~");\r
843           //Selection spans a hidden region\r
844           if(fixedLeft<y1 && (fixedRight>y2 || fixedRight==-1))\r
845           {\r
846             if(startres>=y2)\r
847             {\r
848               fixedLeft = y2;\r
849             }\r
850             else\r
851             {\r
852              fixedRight = y2 - 1;\r
853            }\r
854           }\r
855       }\r
856 \r
857 \r
858       if (groupEditing)\r
859       {\r
860         Vector vseqs = sg.getSequences(av.hiddenRepSequences);\r
861         int g, groupSize = vseqs.size();\r
862         SequenceI[] groupSeqs = new SequenceI[groupSize];\r
863         for (g = 0; g < groupSeqs.length; g++)\r
864           groupSeqs[g] = (SequenceI) vseqs.elementAt(g);\r
865 \r
866         // drag to right\r
867         if (insertGap)\r
868         {\r
869             //If the user has selected the whole sequence, and is dragging to\r
870             // the right, we can still extend the alignment and selectionGroup\r
871             if(   sg.getStartRes() == 0\r
872                   && sg.getEndRes() == fixedRight\r
873                   && sg.getEndRes() == av.alignment.getWidth()-1\r
874                )\r
875             {\r
876               sg.setEndRes(av.alignment.getWidth() + startres - lastres);\r
877               fixedRight = sg.getEndRes();\r
878             }\r
879 \r
880           // Is it valid with fixed columns??\r
881           // Find the next gap before the end\r
882           // of the visible region boundary\r
883           boolean blank = false;\r
884           for (fixedRight = fixedRight;\r
885                fixedRight > lastres;\r
886                fixedRight--)\r
887           {\r
888             blank = true;\r
889 \r
890             for (g = 0; g < groupSize; g++)\r
891             {\r
892               for (int j = 0; j < startres - lastres; j++)\r
893               {\r
894                 if (!jalview.util.Comparison.isGap(\r
895                     groupSeqs[g].getCharAt(fixedRight - j)))\r
896                 {\r
897                   blank = false;\r
898                   break;\r
899                 }\r
900               }\r
901             }\r
902             if (blank)\r
903               break;\r
904           }\r
905 \r
906           if (!blank)\r
907           {\r
908             if(sg.getSize() == av.alignment.getHeight()  )\r
909             {\r
910               if((av.hasHiddenColumns\r
911                   && startres<av.getColumnSelection().getHiddenBoundaryRight(startres)))\r
912               {\r
913                 endEditing();\r
914                 return;\r
915               }\r
916 \r
917               int alWidth = av.alignment.getWidth();\r
918               if(av.hasHiddenRows)\r
919               {\r
920                 int hwidth = av.alignment.getHiddenSequences().getWidth();\r
921                 if(hwidth>alWidth)\r
922                   alWidth = hwidth;\r
923               }\r
924               //We can still insert gaps if the selectionGroup\r
925               //contains all the sequences\r
926               sg.setEndRes(sg.getEndRes()+startres-lastres);\r
927               fixedRight = alWidth+startres-lastres;\r
928             }\r
929             else\r
930             {\r
931               endEditing();\r
932               return;\r
933             }\r
934           }\r
935         }\r
936 \r
937 \r
938         // drag to left\r
939         else if(!insertGap)\r
940         {\r
941           /// Are we able to delete?\r
942           // ie are all columns blank?\r
943 \r
944           for (g = 0; g < groupSize; g++)\r
945           {\r
946             for (int j = startres; j < lastres; j++)\r
947             {\r
948               if (groupSeqs[g].getLength() <= j)\r
949               {\r
950                 continue;\r
951               }\r
952 \r
953               if (!jalview.util.Comparison.isGap(\r
954                   groupSeqs[g].getCharAt(j)))\r
955               {\r
956                 // Not a gap, block edit not valid\r
957                 endEditing();\r
958                 return;\r
959               }\r
960             }\r
961           }\r
962         }\r
963 \r
964           if (insertGap)\r
965           {\r
966             // dragging to the right\r
967             if (fixedColumns && fixedRight != -1)\r
968             {\r
969               for (int j = lastres; j < startres; j++)\r
970               {\r
971                   insertChar(j, groupSeqs, fixedRight);\r
972               }\r
973             }\r
974             else\r
975             {\r
976               editCommand.appendEdit(EditCommand.INSERT_GAP,\r
977                                      groupSeqs,\r
978                                      startres, startres-lastres,\r
979                                      av.alignment,\r
980                                      true);\r
981             }\r
982           }\r
983           else\r
984           {\r
985             // dragging to the left\r
986             if (fixedColumns && fixedRight != -1)\r
987             {\r
988               for (int j = lastres; j > startres; j--)\r
989               {\r
990                 deleteChar(startres, groupSeqs, fixedRight);\r
991               }\r
992             }\r
993             else\r
994               editCommand.appendEdit(EditCommand.DELETE_GAP,\r
995                                      groupSeqs,\r
996                                      startres, lastres - startres,\r
997                                      av.alignment,\r
998                                      true);\r
999 \r
1000           }\r
1001       }\r
1002       else /////Editing a single sequence///////////\r
1003       {\r
1004         if (insertGap)\r
1005         {\r
1006           // dragging to the right\r
1007           if (fixedColumns && fixedRight != -1)\r
1008           {\r
1009             for (int j = lastres; j < startres; j++)\r
1010             {\r
1011               insertChar(j, new SequenceI[]{seq}, fixedRight);\r
1012             }\r
1013           }\r
1014           else\r
1015           {\r
1016             editCommand.appendEdit(EditCommand.INSERT_GAP,\r
1017                                    new SequenceI[]\r
1018                                    {seq},\r
1019                                    lastres, startres-lastres,\r
1020                                    av.alignment,\r
1021                                    true);\r
1022           }\r
1023         }\r
1024         else\r
1025         {\r
1026           // dragging to the left\r
1027           if (fixedColumns && fixedRight != -1)\r
1028           {\r
1029             for (int j = lastres; j > startres; j--)\r
1030             {\r
1031               if (!jalview.util.Comparison.isGap(seq.getCharAt(startres)))\r
1032               {\r
1033                 endEditing();\r
1034                 break;\r
1035               }\r
1036               deleteChar(startres, new SequenceI[]{seq}, fixedRight);\r
1037             }\r
1038           }\r
1039           else\r
1040           {\r
1041             //could be a keyboard edit trying to delete none gaps\r
1042             int max=0;\r
1043             for(int m = startres; m<lastres; m++)\r
1044             {\r
1045               if(!jalview.util.Comparison.isGap(seq.getCharAt(m)))\r
1046                 break;\r
1047               max++;\r
1048             }\r
1049 \r
1050             if (max>0)\r
1051             {\r
1052               editCommand.appendEdit(EditCommand.DELETE_GAP,\r
1053                                      new SequenceI[]\r
1054                                      {seq},\r
1055                                      startres, max,\r
1056                                      av.alignment,\r
1057                                      true);\r
1058             }\r
1059           }\r
1060         }\r
1061       }\r
1062 \r
1063       lastres = startres;\r
1064       seqCanvas.repaint();\r
1065   }\r
1066 \r
1067 \r
1068 \r
1069   void insertChar(int j, SequenceI [] seq, int fixedColumn)\r
1070   {\r
1071     int blankColumn = fixedColumn;\r
1072     for(int s=0; s<seq.length; s++)\r
1073     {\r
1074       //Find the next gap before the end of the visible region boundary\r
1075       //If lastCol > j, theres a boundary after the gap insertion\r
1076 \r
1077       for (blankColumn = fixedColumn; blankColumn > j; blankColumn--)\r
1078       {\r
1079         if (jalview.util.Comparison.isGap(seq[s].getCharAt(blankColumn)))\r
1080         {\r
1081           //Theres a space, so break and insert the gap\r
1082           break;\r
1083         }\r
1084       }\r
1085 \r
1086       if (blankColumn <= j)\r
1087       {\r
1088         blankColumn = fixedColumn;\r
1089         endEditing();\r
1090         return;\r
1091       }\r
1092     }\r
1093 \r
1094     editCommand.appendEdit(EditCommand.DELETE_GAP,\r
1095                            seq,\r
1096                            blankColumn, 1, av.alignment, true);\r
1097 \r
1098     editCommand.appendEdit(EditCommand.INSERT_GAP,\r
1099                            seq,\r
1100                            j, 1, av.alignment,\r
1101                            true);\r
1102 \r
1103   }\r
1104 \r
1105   void deleteChar(int j, SequenceI [] seq, int fixedColumn)\r
1106   {\r
1107 \r
1108     editCommand.appendEdit(EditCommand.DELETE_GAP,\r
1109                            seq,\r
1110                            j, 1, av.alignment, true);\r
1111 \r
1112     editCommand.appendEdit(EditCommand.INSERT_GAP,\r
1113                            seq,\r
1114                            fixedColumn, 1, av.alignment, true);\r
1115   }\r
1116 \r
1117 \r
1118 //////////////////////////////////////////\r
1119 /////Everything below this is for defining the boundary of the rubberband\r
1120 //////////////////////////////////////////\r
1121   public void doMousePressedDefineMode(MouseEvent evt)\r
1122   {\r
1123     if (scrollThread != null)\r
1124     {\r
1125       scrollThread.running = false;\r
1126       scrollThread = null;\r
1127     }\r
1128 \r
1129     int res = findRes(evt);\r
1130     int seq = findSeq(evt);\r
1131     oldSeq = seq;\r
1132     startWrapBlock=wrappedBlock;\r
1133 \r
1134     if(seq==-1)\r
1135       return;\r
1136 \r
1137     SequenceI sequence = (Sequence) av.getAlignment().getSequenceAt(seq);\r
1138 \r
1139     if (sequence == null || res > sequence.getLength())\r
1140     {\r
1141       return;\r
1142     }\r
1143 \r
1144     stretchGroup = av.getSelectionGroup();\r
1145 \r
1146     if (stretchGroup == null)\r
1147     {\r
1148       stretchGroup = av.alignment.findGroup(sequence);\r
1149       if (stretchGroup != null && res > stretchGroup.getStartRes() &&\r
1150           res < stretchGroup.getEndRes())\r
1151       {\r
1152         av.setSelectionGroup(stretchGroup);\r
1153       }\r
1154       else\r
1155       {\r
1156         stretchGroup = null;\r
1157       }\r
1158     }\r
1159 \r
1160     else if (!stretchGroup.getSequences(null).contains(sequence)\r
1161              || stretchGroup.getStartRes() > res\r
1162              || stretchGroup.getEndRes() < res)\r
1163     {\r
1164       stretchGroup = null;\r
1165 \r
1166       SequenceGroup[] allGroups = av.alignment.findAllGroups(sequence);\r
1167 \r
1168       if (allGroups != null)\r
1169       {\r
1170         for (int i = 0; i < allGroups.length; i++)\r
1171         {\r
1172           if (allGroups[i].getStartRes() <= res &&\r
1173               allGroups[i].getEndRes() >= res)\r
1174           {\r
1175             stretchGroup = allGroups[i];\r
1176             break;\r
1177           }\r
1178         }\r
1179       }\r
1180       av.setSelectionGroup(stretchGroup);\r
1181     }\r
1182 \r
1183 \r
1184     // DETECT RIGHT MOUSE BUTTON IN AWT\r
1185     if ( (evt.getModifiers() & InputEvent.BUTTON3_MASK) ==\r
1186              InputEvent.BUTTON3_MASK)\r
1187     {\r
1188       Vector allFeatures = getAllFeaturesAtRes(sequence,\r
1189                                                sequence.findPosition(res));\r
1190 \r
1191       Vector links = null;\r
1192       if(allFeatures!=null)\r
1193       {\r
1194         for (int i = 0; i < allFeatures.size(); i++)\r
1195         {\r
1196           SequenceFeature sf = (SequenceFeature) allFeatures.elementAt(i);\r
1197           if (sf.links != null)\r
1198           {\r
1199             links = new Vector();\r
1200             for (int j = 0; j < sf.links.size(); j++)\r
1201             {\r
1202               links.addElement(sf.links.elementAt(j));\r
1203             }\r
1204           }\r
1205         }\r
1206       }\r
1207       APopupMenu popup = new APopupMenu(ap, null, links);\r
1208       this.add(popup);\r
1209       popup.show(this, evt.getX(), evt.getY());\r
1210       ap.repaint();\r
1211       return;\r
1212     }\r
1213 \r
1214     if (av.cursorMode)\r
1215     {\r
1216       seqCanvas.cursorX = findRes(evt);\r
1217       seqCanvas.cursorY = findSeq(evt);\r
1218       seqCanvas.repaint();\r
1219       return;\r
1220     }\r
1221 \r
1222       //Only if left mouse button do we want to change group sizes\r
1223 \r
1224       if (stretchGroup == null)\r
1225       {\r
1226         // define a new group here\r
1227         SequenceGroup sg = new SequenceGroup();\r
1228         sg.setStartRes(res);\r
1229         sg.setEndRes(res);\r
1230         sg.addSequence(sequence, false);\r
1231         av.setSelectionGroup(sg);\r
1232         stretchGroup = sg;\r
1233 \r
1234         if (av.getConservationSelected())\r
1235         {\r
1236           SliderPanel.setConservationSlider(ap, av.getGlobalColourScheme(),\r
1237                                             "Background");\r
1238         }\r
1239         if (av.getAbovePIDThreshold())\r
1240         {\r
1241           SliderPanel.setPIDSliderSource(ap, av.getGlobalColourScheme(),\r
1242                                          "Background");\r
1243         }\r
1244 \r
1245       }\r
1246   }\r
1247 \r
1248   public void doMouseReleasedDefineMode(MouseEvent evt)\r
1249   {\r
1250     if (stretchGroup == null)\r
1251     {\r
1252         return;\r
1253     }\r
1254 \r
1255     if(stretchGroup.cs!=null)\r
1256     {\r
1257       if (stretchGroup.cs instanceof ClustalxColourScheme)\r
1258       {\r
1259         ( (ClustalxColourScheme) stretchGroup.cs).resetClustalX(\r
1260             stretchGroup.getSequences(av.hiddenRepSequences),\r
1261             stretchGroup.getWidth());\r
1262       }\r
1263 \r
1264       if (stretchGroup.cs instanceof Blosum62ColourScheme\r
1265           || stretchGroup.cs instanceof PIDColourScheme\r
1266           || stretchGroup.cs.conservationApplied()\r
1267           || stretchGroup.cs.getThreshold() > 0)\r
1268         stretchGroup.recalcConservation();\r
1269 \r
1270 \r
1271       if (stretchGroup.cs.conservationApplied())\r
1272       {\r
1273         SliderPanel.setConservationSlider(ap, stretchGroup.cs,\r
1274                                           stretchGroup.getName());\r
1275         stretchGroup.recalcConservation();\r
1276       }\r
1277       else\r
1278       {\r
1279         SliderPanel.setPIDSliderSource(ap, stretchGroup.cs,\r
1280                                        stretchGroup.getName());\r
1281       }\r
1282     }\r
1283     changeEndRes = false;\r
1284     changeStartRes = false;\r
1285     stretchGroup = null;\r
1286     PaintRefresher.Refresh(ap, av.getSequenceSetId());\r
1287     ap.repaint();\r
1288   }\r
1289 \r
1290   public void doMouseDraggedDefineMode(MouseEvent evt)\r
1291   {\r
1292     int res = findRes(evt);\r
1293     int y = findSeq(evt);\r
1294 \r
1295     if(wrappedBlock!=startWrapBlock)\r
1296       return;\r
1297 \r
1298      if (stretchGroup == null)\r
1299      {\r
1300           return;\r
1301      }\r
1302 \r
1303      mouseDragging = true;\r
1304 \r
1305 \r
1306       if(y > av.alignment.getHeight())\r
1307       {\r
1308         y = av.alignment.getHeight() -1;\r
1309       }\r
1310 \r
1311       if(res>=av.alignment.getWidth())\r
1312         res = av.alignment.getWidth()-1;\r
1313 \r
1314       if (stretchGroup.getEndRes() == res)\r
1315       {\r
1316           // Edit end res position of selected group\r
1317           changeEndRes = true;\r
1318       }\r
1319       else if (stretchGroup.getStartRes() == res)\r
1320       {\r
1321           // Edit start res position of selected group\r
1322           changeStartRes = true;\r
1323       }\r
1324 \r
1325       if (res < 0)\r
1326       {\r
1327           res = 0;\r
1328       }\r
1329 \r
1330       if (changeEndRes)\r
1331       {\r
1332           if (res > (stretchGroup.getStartRes() - 1))\r
1333           {\r
1334               stretchGroup.setEndRes(res);\r
1335           }\r
1336       }\r
1337       else if (changeStartRes)\r
1338       {\r
1339           if (res < (stretchGroup.getEndRes() + 1))\r
1340           {\r
1341               stretchGroup.setStartRes(res);\r
1342           }\r
1343       }\r
1344 \r
1345       int dragDirection = 0;\r
1346 \r
1347       if (y > oldSeq)\r
1348       {\r
1349           dragDirection = 1;\r
1350       }\r
1351       else if (y < oldSeq)\r
1352       {\r
1353           dragDirection = -1;\r
1354       }\r
1355 \r
1356 \r
1357       while ((y != oldSeq) && (oldSeq > -1) && (y < av.alignment.getHeight()))\r
1358       {\r
1359           // This routine ensures we don't skip any sequences, as the\r
1360           // selection is quite slow.\r
1361           Sequence seq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);\r
1362 \r
1363           oldSeq += dragDirection;\r
1364 \r
1365           if(oldSeq<0)\r
1366             break;\r
1367 \r
1368           Sequence nextSeq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);\r
1369 \r
1370           if (stretchGroup.getSequences(null).contains(nextSeq))\r
1371           {\r
1372               stretchGroup.deleteSequence(seq, false);\r
1373           }\r
1374           else\r
1375           {\r
1376               if (seq != null)\r
1377               {\r
1378                   stretchGroup.addSequence(seq, false);\r
1379               }\r
1380 \r
1381               stretchGroup.addSequence(nextSeq, false);\r
1382           }\r
1383       }\r
1384 \r
1385       if(oldSeq < 0)\r
1386         oldSeq = -1;\r
1387 \r
1388 \r
1389       if(res>av.endRes || res<av.startRes\r
1390           || y<av.startSeq || y>av.endSeq)\r
1391       {\r
1392         mouseExited(evt);\r
1393       }\r
1394 \r
1395       if (scrollThread != null)\r
1396       {\r
1397         scrollThread.setEvent(evt);\r
1398       }\r
1399 \r
1400       seqCanvas.repaint();\r
1401     }\r
1402 \r
1403     public void mouseEntered(MouseEvent e)\r
1404     {\r
1405       if (oldSeq < 0)\r
1406         oldSeq = 0;\r
1407 \r
1408       if (scrollThread != null)\r
1409       {\r
1410         scrollThread.running = false;\r
1411         scrollThread = null;\r
1412       }\r
1413     }\r
1414 \r
1415   public void mouseExited(MouseEvent e)\r
1416   {\r
1417     if (av.getWrapAlignment())\r
1418     {\r
1419       return;\r
1420     }\r
1421 \r
1422     if (mouseDragging && scrollThread==null)\r
1423     {\r
1424       scrollThread = new ScrollThread();\r
1425     }\r
1426   }\r
1427 \r
1428   void scrollCanvas(MouseEvent evt)\r
1429   {\r
1430     if(evt==null)\r
1431     {\r
1432       if(scrollThread!=null)\r
1433       {\r
1434         scrollThread.running = false;\r
1435         scrollThread = null;\r
1436       }\r
1437       mouseDragging = false;\r
1438     }\r
1439     else\r
1440     {\r
1441       if (scrollThread == null)\r
1442         scrollThread = new ScrollThread();\r
1443 \r
1444       mouseDragging = true;\r
1445       scrollThread.setEvent(evt);\r
1446     }\r
1447 \r
1448     }\r
1449 \r
1450   // this class allows scrolling off the bottom of the visible alignment\r
1451   class ScrollThread\r
1452       extends Thread\r
1453   {\r
1454     MouseEvent evt;\r
1455     boolean running = false;\r
1456     public ScrollThread()\r
1457     {\r
1458       start();\r
1459     }\r
1460 \r
1461     public void setEvent(MouseEvent e)\r
1462     {\r
1463       evt = e;\r
1464     }\r
1465 \r
1466     public void stopScrolling()\r
1467     {\r
1468       running = false;\r
1469     }\r
1470 \r
1471     public void run()\r
1472     {\r
1473       running = true;\r
1474       while (running)\r
1475       {\r
1476 \r
1477         if (evt != null)\r
1478         {\r
1479 \r
1480           if (mouseDragging && evt.getY() < 0 && av.getStartSeq() > 0)\r
1481           {\r
1482             running = ap.scrollUp(true);\r
1483           }\r
1484 \r
1485           if (mouseDragging && evt.getY() >= getSize().height &&\r
1486               av.alignment.getHeight() > av.getEndSeq())\r
1487           {\r
1488             running = ap.scrollUp(false);\r
1489           }\r
1490 \r
1491           if (mouseDragging && evt.getX() < 0)\r
1492           {\r
1493             running = ap.scrollRight(false);\r
1494           }\r
1495 \r
1496           else if (mouseDragging && evt.getX() >= getSize().width)\r
1497           {\r
1498             running = ap.scrollRight(true);\r
1499           }\r
1500         }\r
1501 \r
1502         try\r
1503         {\r
1504           Thread.sleep(75);\r
1505         }\r
1506         catch (Exception ex)\r
1507         {}\r
1508       }\r
1509     }\r
1510   }\r
1511 \r
1512 }\r