check that mouse is over sequence if unaligned
[jalview.git] / src / jalview / gui / SeqPanel.java
1 package jalview.gui;\r
2 \r
3 import java.awt.*;\r
4 import java.awt.event.*;\r
5 import jalview.datamodel.*;\r
6 import javax.swing.*;\r
7 import java.util.*;\r
8 import jalview.schemes.*;\r
9 import jalview.analysis.*;\r
10 \r
11 \r
12 public class SeqPanel extends JPanel\r
13 {\r
14 \r
15   public    SeqCanvas         seqCanvas;\r
16   public    AlignmentPanel    ap;\r
17 \r
18   protected int startres;\r
19   protected int lastres;\r
20   protected int endres;\r
21 \r
22   protected int startseq;\r
23   protected int padseq;\r
24 \r
25   protected AlignViewport av;\r
26 \r
27   // if character is inserted or deleted, we will need to recalculate the conservation\r
28   int seqEditOccurred = -1;\r
29 \r
30   public SeqPanel(AlignViewport avp, AlignmentPanel p) {\r
31     this.av         = avp;\r
32 \r
33     seqCanvas  = new SeqCanvas(avp);\r
34     setLayout(new BorderLayout());\r
35     add(seqCanvas, BorderLayout.CENTER);\r
36 \r
37     ap = p;\r
38 \r
39     addMouseMotionListener( new MouseMotionAdapter()\r
40     {\r
41       public void mouseMoved(MouseEvent evt)\r
42       {\r
43        if(av.getWrapAlignment())\r
44          return;\r
45         doMouseMoved(evt);    }\r
46 \r
47       public void mouseDragged(MouseEvent evt)\r
48       {\r
49         if(av.getWrapAlignment())\r
50          return;\r
51         if(evt.isShiftDown() || evt.isAltDown() || evt.isControlDown())\r
52           doMouseDragged(evt);\r
53         else\r
54           doMouseDraggedDefineMode(evt);\r
55       }\r
56     });\r
57 \r
58     addMouseListener( new MouseAdapter()\r
59     {\r
60       public void mouseReleased(MouseEvent evt)\r
61       {\r
62         if(av.getWrapAlignment())\r
63          return;\r
64         if(evt.isShiftDown() || evt.isAltDown() || evt.isControlDown())\r
65           doMouseReleased(evt);\r
66         else\r
67           doMouseReleasedDefineMode(evt);\r
68       }\r
69       public void mousePressed(MouseEvent evt)\r
70       {\r
71         if(av.getWrapAlignment())\r
72          return;\r
73         if(evt.isShiftDown() || evt.isAltDown() || evt.isControlDown())\r
74           doMousePressed(evt);\r
75         else\r
76           doMousePressedDefineMode(evt);\r
77       }\r
78 \r
79     });\r
80     repaint();\r
81   }\r
82 \r
83 \r
84   public void doMouseReleased(MouseEvent evt) {\r
85 \r
86     int x = evt.getX();\r
87     int res = x/av.getCharWidth() + av.getStartRes();\r
88 \r
89     endres = res;\r
90 \r
91     startseq = -1;\r
92     startres = -1;\r
93     lastres  = -1;\r
94     if(seqEditOccurred>-1)\r
95       updateConservation(seqEditOccurred);\r
96 \r
97     seqEditOccurred = -1;\r
98 \r
99     ap.RefreshPanels();\r
100     repaint();\r
101 \r
102   }\r
103 \r
104   public void doMousePressed(MouseEvent evt) {\r
105     ap.alignFrame.addHistoryItem("sequence edit");\r
106     int seq;\r
107     int res;\r
108 \r
109     int x = evt.getX();\r
110     int y = evt.getY();\r
111 \r
112     res = x/av.getCharWidth() + av.getStartRes();\r
113     seq = y/av.getCharHeight() + av.getStartSeq();\r
114 \r
115     if (seq < av.getAlignment().getHeight() &&\r
116         res < av.getAlignment().getSequenceAt(seq).getLength())\r
117     {\r
118       //char resstr = align.getSequenceAt(seq).getSequence().charAt(res);\r
119       // Find the residue's position in the sequence (res is the position\r
120       // in the alignment\r
121 \r
122       startseq = seq;\r
123 \r
124       if (startseq == (av.getAlignment().getHeight() - 1))\r
125         padseq = 1;\r
126       else\r
127         padseq = 1;\r
128 \r
129       startres = res;\r
130       lastres = res;\r
131 \r
132     }\r
133     else\r
134     {\r
135       startseq = -1;\r
136       startres = -1;\r
137       lastres = -1;\r
138     }\r
139 \r
140     return;\r
141   }\r
142 \r
143   public void doMouseMoved(MouseEvent evt)\r
144   {\r
145     int res=0, seq=0;\r
146     int x = evt.getX();\r
147     int y = evt.getY();\r
148     if(av.wrapAlignment)\r
149     {\r
150       y -= 2*av.charHeight;\r
151       int chunkHeight = (av.getAlignment().getHeight()+2)*av.charHeight;\r
152 \r
153 \r
154       res =   (int)((y/chunkHeight)*(getWidth()/av.charWidth)) +  x/av.getCharWidth() + av.getStartRes();\r
155 \r
156       y %= chunkHeight;\r
157       seq =     y / av.getCharHeight() + av.getStartSeq();\r
158 \r
159       //   chunkHeight =  (da.getHeight() + 2)*charHeight;\r
160       //  startx += chunkWidth;\r
161     }\r
162     else\r
163     {\r
164       res = x / av.getCharWidth()  + av.getStartRes();\r
165       seq = y / av.getCharHeight() + av.getStartSeq();\r
166     }\r
167 \r
168 \r
169     if(seq>=av.getAlignment().getHeight())\r
170       return;\r
171 \r
172     SequenceI sequence = av.getAlignment().getSequenceAt(seq);\r
173     if(res>sequence.getLength())\r
174       return;\r
175 \r
176     Object obj = ResidueProperties.aa2Triplet.get( sequence.getCharAt(res)+"" ) ;\r
177     String aa = "";\r
178     if(obj!=null)\r
179          aa = obj.toString();\r
180 \r
181     StringBuffer text = new StringBuffer("Sequence " +(seq+1)+" ID: "+sequence.getName());\r
182     if(aa!="")\r
183       text.append("  Residue: "+aa+" ("+  av.getAlignment().getSequenceAt(seq).findPosition(res)+")");\r
184 \r
185     ap.alignFrame.statusBar.setText(text.toString());\r
186 \r
187     // use aa to see if the mouse pointer is on a\r
188     if(  av.showSequenceFeatures)\r
189     {\r
190       Vector features = sequence.getSequenceFeatures();\r
191       Enumeration e = features.elements();\r
192       StringBuffer sbuffer = new StringBuffer();\r
193 \r
194 \r
195       while (e.hasMoreElements())\r
196       {\r
197         SequenceFeature sf = (SequenceFeature) e.nextElement();\r
198         if (sf.getStart() <= sequence.findPosition(res) &&\r
199             sf.getEnd() >= sequence.findPosition(res))\r
200         {\r
201           if(sbuffer.length()>0)\r
202             sbuffer.append("; ");\r
203           sbuffer.append(sf.getType() + " " + sf.getDescription());\r
204           if(sf.getStatus().length()>0)\r
205             sbuffer.append(" ("+sf.getStatus()+")");\r
206         }\r
207 \r
208       }\r
209 \r
210       ToolTipManager.sharedInstance().registerComponent(this);\r
211       this.setToolTipText(sbuffer.toString());\r
212     }\r
213 \r
214 \r
215   }\r
216 \r
217   public void doMouseDragged(MouseEvent evt) {\r
218     // If we're dragging we're editing\r
219 \r
220     if(lastres==-1)\r
221       return;\r
222 \r
223     int x = evt.getX();\r
224 \r
225     int res = x/av.getCharWidth() + av.getStartRes();\r
226     if (res < 0)\r
227       res = 0;\r
228 \r
229     if (res != lastres)\r
230     {\r
231         // Group editing\r
232         if (evt.isAltDown() || evt.isControlDown())\r
233         {\r
234           SequenceGroup sg = av.getAlignment().findGroup(startseq);\r
235           if (sg != null)\r
236           {\r
237             boolean deleteAllowed = false;\r
238             if (res < av.getAlignment().getWidth() && res < lastres)\r
239             {\r
240               /// Are we able to delete?\r
241               boolean allGaps = true;\r
242               for (int i = 0; i < sg.getSize(); i++)\r
243               {\r
244                 SequenceI s = sg.getSequenceAt(i);\r
245                 for (int j = lastres-1; j >= res && allGaps; j--)\r
246                 {\r
247                     if (!jalview.util.Comparison.isGap(s.getSequence().charAt(j)))\r
248                     {\r
249                       res = j + 1;\r
250                       allGaps = false;\r
251                     }\r
252                 }\r
253 \r
254                 if(!deleteAllowed && allGaps)\r
255                   deleteAllowed = true;\r
256               }\r
257             }\r
258 \r
259             // drag to right\r
260             if (res < av.getAlignment().getWidth() && res > lastres)\r
261                 sg.setEndRes(sg.getEndRes() + 1);\r
262 \r
263             // drag to left\r
264             else if (deleteAllowed && res < av.getAlignment().getWidth() &&\r
265                      res < lastres)\r
266                 sg.setEndRes(sg.getEndRes() - 1);\r
267 \r
268 \r
269 \r
270 \r
271             for (int i = 0; i < sg.getSize(); i++)\r
272             {\r
273               SequenceI s = sg.getSequenceAt(i);\r
274               int k = av.alignment.findIndex(s);\r
275 \r
276               // drag to right\r
277               if (res < av.getAlignment().getWidth() && res > lastres)\r
278                 for (int j = lastres; j < res; j++)\r
279                   insertChar(j, k);\r
280 \r
281               // drag to left\r
282               else if (deleteAllowed && res < av.getAlignment().getWidth() && res < lastres)\r
283               {\r
284                 for (int j = res; j < lastres; j++)\r
285                 {\r
286                   deleteChar(j, k);\r
287                   startres = res;\r
288                 }\r
289               }\r
290             }\r
291           }\r
292         }\r
293         else /////Editing a single sequence///////////\r
294         {\r
295           if (res < av.getAlignment().getWidth() && res > lastres)\r
296           {\r
297             // dragging to the right\r
298             for (int j = lastres; j < res; j++)\r
299               insertChar(j, startseq);\r
300           }\r
301           else if (res < av.getAlignment().getWidth() && res < lastres)\r
302           {\r
303             // dragging to the left\r
304             for (int j = res; j < lastres; j++)\r
305             {\r
306               deleteChar(j, startseq);\r
307               startres = res;\r
308             }\r
309           }\r
310 \r
311         }\r
312 \r
313     }\r
314 \r
315     lastres = res;\r
316     repaint();\r
317   }\r
318 \r
319   public void drawChars(int seqstart, int seqend, int start) {\r
320     seqCanvas.drawPanel(seqCanvas.gg, start,av.getEndRes(),seqstart,seqend,av.getStartRes(),av.getStartSeq(),0);\r
321     repaint();\r
322   }\r
323 \r
324   public void insertChar(int j, int seq)\r
325   {\r
326     av.alignment.getSequenceAt(seq).insertCharAt(j, av.getGapCharacter());\r
327     seqEditOccurred=seq;\r
328   }\r
329 \r
330   public void deleteChar(int j, int seq)\r
331   {\r
332 \r
333     if ( jalview.util.Comparison.isGap( av.alignment.getSequenceAt(seq).getSequence().charAt(j)))\r
334         av.alignment.getSequenceAt(seq).deleteCharAt(j);\r
335 \r
336     av.alignment.getWidth();\r
337     repaint();\r
338     seqEditOccurred=seq;\r
339   }\r
340 \r
341 \r
342   void updateConservation(int i)\r
343   {\r
344   /*  Alignment al = (Alignment) av.getAlignment();\r
345     SequenceGroup sg = av.alignment.findGroup( al.getSequenceAt(i));\r
346     if(sg==null || !(sg.cs instanceof ConservationColourScheme))\r
347       return;\r
348 \r
349     Conservation c = sg.getConservation();\r
350 \r
351     c = new Conservation("All", al.cons,\r
352                          ResidueProperties.propHash, 3, sg.sequences, 0,\r
353                          al.getWidth());\r
354     c.calculate();\r
355     c.verdict(false, 100);\r
356     sg.setConservation(c);\r
357     ConservationColourScheme ccs = (ConservationColourScheme)sg.cs;\r
358     ccs.conserve = c;*/\r
359   }\r
360 \r
361 //////////////////////////////////////////\r
362 /////Everything below this is for defining the boundary of the rubberband\r
363 //////////////////////////////////////////\r
364   int oldSeq = -1;\r
365   public void doMousePressedDefineMode(MouseEvent evt)\r
366   {\r
367     int res = evt.getX()/av.getCharWidth() + av.getStartRes();\r
368     int seq = evt.getY()/av.getCharHeight() + av.getStartSeq();\r
369     oldSeq = seq;\r
370 \r
371     SequenceI sequence = (Sequence) av.getAlignment().getSequenceAt(seq);\r
372     if(res>sequence.getLength())\r
373       return;\r
374 \r
375     stretchGroup = av.getRubberbandGroup();\r
376 \r
377     if(stretchGroup == null)\r
378      {\r
379        stretchGroup = av.alignment.findGroup( sequence );\r
380        av.setRubberbandGroup( stretchGroup );\r
381      }\r
382 \r
383     else if(!stretchGroup.sequences.contains(sequence)\r
384             || stretchGroup.getStartRes()>res\r
385             || stretchGroup.getEndRes()<res)\r
386      {\r
387        stretchGroup = null;\r
388 \r
389        SequenceGroup[] allGroups = av.alignment.findAllGroups( sequence );\r
390 \r
391        if (allGroups != null)\r
392          for (int i = 0; i < allGroups.length; i++)\r
393            if (allGroups[i].getStartRes() <= res &&\r
394                allGroups[i].getEndRes() >= res)\r
395            {\r
396              stretchGroup = allGroups[i];\r
397              av.setRubberbandGroup(stretchGroup);\r
398              break;\r
399            }\r
400      }\r
401 \r
402     if(stretchGroup==null)\r
403     {\r
404       // define a new group here\r
405       SequenceGroup sg = new SequenceGroup();\r
406       sg.setStartRes(res);\r
407       sg.setEndRes(res);\r
408       sg.addSequence( sequence );\r
409       av.setRubberbandGroup( sg );\r
410       stretchGroup = sg;\r
411 \r
412       if(av.getConservationSelected())\r
413         Desktop.setConservationSliderSource(ap, av.getGlobalColourScheme(), "Background");\r
414       else if(av.getGlobalColourScheme()!=null && av.getGlobalColourScheme().canThreshold())\r
415       {\r
416         ResidueColourScheme rcs = (ResidueColourScheme) av.getGlobalColourScheme();\r
417         int threshold = rcs.getThreshold();\r
418         if (threshold > 0)\r
419           Desktop.setPIDSliderSource(ap, av.getGlobalColourScheme(), "Background");\r
420       }\r
421 \r
422     }\r
423     else if( javax.swing.SwingUtilities.isRightMouseButton(evt))\r
424     {\r
425         jalview.gui.PopupMenu pop = new jalview.gui.PopupMenu( ap , null);\r
426         pop.show(this, evt.getX(), evt.getY());\r
427 \r
428     // edit the properties of existing group\r
429     }\r
430 \r
431     if(stretchGroup!=null && stretchGroup.getEndRes()==res)\r
432       // Edit end res position of selected group\r
433       changeEndRes = true;\r
434 \r
435    else if(stretchGroup!=null && stretchGroup.getStartRes()==res)\r
436       // Edit end res position of selected group\r
437       changeStartRes = true;\r
438 \r
439 \r
440     seqCanvas.paintFlag = true;\r
441     repaint();\r
442 \r
443   }\r
444 \r
445   boolean changeEndSeq = false;\r
446   boolean changeStartSeq = false;\r
447   boolean changeEndRes = false;\r
448   boolean changeStartRes = false;\r
449   SequenceGroup stretchGroup = null;\r
450 \r
451   public void doMouseReleasedDefineMode(MouseEvent evt)\r
452   {\r
453     if(stretchGroup==null)\r
454       return;\r
455 \r
456     if(stretchGroup.cs instanceof ClustalxColourScheme)\r
457     {\r
458       stretchGroup.cs = new ClustalxColourScheme(stretchGroup.sequences, av.alignment.getWidth());\r
459       seqCanvas.paintFlag = true;\r
460       repaint();\r
461     }\r
462 \r
463     else if(stretchGroup.cs instanceof ConservationColourScheme)\r
464     {\r
465       ConservationColourScheme ccs = (ConservationColourScheme)stretchGroup.cs;\r
466 \r
467       Conservation c = new Conservation("Group",\r
468                                         ResidueProperties.propHash, 3, stretchGroup.sequences, 0,\r
469                                         av.alignment.getWidth() );\r
470 \r
471        c.calculate();\r
472        c.verdict(false, 100);\r
473        ccs = new ConservationColourScheme(c, ccs.cs);\r
474 \r
475        stretchGroup.cs = ccs;\r
476 \r
477 \r
478        Desktop.setConservationSliderSource(ap, stretchGroup.cs, stretchGroup.getName()) ;\r
479 \r
480        seqCanvas.paintFlag = true;\r
481        repaint();\r
482     }\r
483     else\r
484     {\r
485       if(stretchGroup.cs !=null && stretchGroup.cs.canThreshold())\r
486       {\r
487         ResidueColourScheme rcs =  (ResidueColourScheme) stretchGroup.cs;\r
488         int threshold = rcs.getThreshold();\r
489         if(threshold>0)\r
490           Desktop.setPIDSliderSource(ap, stretchGroup.cs, stretchGroup.getName());\r
491       }\r
492 \r
493     }\r
494 \r
495 \r
496     changeEndRes = false;\r
497     changeStartRes = false;\r
498     stretchGroup = null;\r
499   }\r
500 \r
501 \r
502   boolean remove = false;\r
503   public void doMouseDraggedDefineMode(MouseEvent evt)\r
504   {\r
505     int res = evt.getX()/av.getCharWidth() + av.getStartRes();\r
506     int y = evt.getY()/av.getCharHeight() + av.getStartSeq();\r
507 \r
508     if(stretchGroup==null)\r
509       return;\r
510 \r
511     if(stretchGroup.getEndRes()==res)\r
512       // Edit end res position of selected group\r
513       changeEndRes = true;\r
514 \r
515     else if(stretchGroup.getStartRes()==res)\r
516       // Edit start res position of selected group\r
517       changeStartRes = true;\r
518 \r
519 \r
520     if(res<av.getStartRes())\r
521       res = av.getStartRes();\r
522     else if(res>av.getEndRes())\r
523       res = av.getEndRes();\r
524 \r
525     if(changeEndRes)\r
526     {\r
527       if(res>stretchGroup.getStartRes()-1)\r
528         stretchGroup.setEndRes( res );\r
529     }\r
530     else if(changeStartRes)\r
531     {\r
532       if(res<stretchGroup.getEndRes()+1)\r
533         stretchGroup.setStartRes( res );\r
534     }\r
535 \r
536 \r
537     int dragDirection = 0;\r
538     if (y > oldSeq)\r
539       dragDirection = 1;\r
540     else if (y < oldSeq)\r
541       dragDirection = -1;\r
542 \r
543     while (y != oldSeq)\r
544     {\r
545       // This routine ensures we don't skip any sequences, as the\r
546       // selection is quite slow.\r
547       Sequence seq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);\r
548 \r
549       oldSeq += dragDirection;\r
550       Sequence nextSeq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);\r
551 \r
552       if (stretchGroup.sequences.contains(nextSeq))\r
553       {\r
554         stretchGroup.deleteSequence(seq);\r
555         stretchGroup.deleteSequence(nextSeq);\r
556       }\r
557       else\r
558       {\r
559         stretchGroup.addSequence(seq);\r
560         stretchGroup.addSequence(nextSeq);\r
561       }\r
562     }\r
563     oldSeq = y;\r
564 \r
565     seqCanvas.paintFlag = true;\r
566     repaint();\r
567   }\r
568 \r
569 \r
570 }\r
571 \r
572 \r
573 \r
574 \r