Selection of sequences is continuous
[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 jalview.schemes.*;\r
8 import jalview.analysis.*;\r
9 \r
10 \r
11 public class SeqPanel extends JPanel\r
12 {\r
13 \r
14   public    SeqCanvas         seqCanvas;\r
15   public    AlignmentPanel    parent;\r
16 \r
17   protected int startres;\r
18   protected int lastres;\r
19   protected int endres;\r
20 \r
21   protected int startseq;\r
22   protected int padseq;\r
23 \r
24   public    boolean editFlag;\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     parent = p;\r
38 \r
39     addMouseMotionListener( new MouseMotionAdapter()\r
40     {\r
41       public void mouseMoved(MouseEvent evt)\r
42       {   doMouseMoved(evt);    }\r
43 \r
44       public void mouseDragged(MouseEvent evt)\r
45       {\r
46         if(av.groupDefiningMode)\r
47           doMouseDraggedDefineMode(evt);\r
48         else\r
49           doMouseDragged(evt);\r
50       }\r
51     });\r
52 \r
53     addMouseListener( new MouseAdapter()\r
54     {\r
55       public void mouseReleased(MouseEvent evt)\r
56       {\r
57         if(av.groupDefiningMode)\r
58           doMouseReleasedDefineMode(evt);\r
59         else\r
60           doMouseReleased(evt);\r
61       }\r
62       public void mousePressed(MouseEvent evt)\r
63       {\r
64         if(av.groupDefiningMode)\r
65           doMousePressedDefineMode(evt);\r
66         else\r
67           doMousePressed(evt);\r
68       }\r
69 \r
70     });\r
71     repaint();\r
72   }\r
73 \r
74 \r
75   public void doMouseReleased(MouseEvent evt) {\r
76 \r
77     int x = evt.getX();\r
78     int res = x/av.getCharWidth() + av.getStartRes();\r
79 \r
80     endres = res;\r
81 \r
82       // This is to detect edits - we're at the end of an edit if mouse is up\r
83     editFlag = false;\r
84     startseq = -1;\r
85     startres = -1;\r
86     lastres  = -1;\r
87     if(seqEditOccurred>-1)\r
88       updateConservation(seqEditOccurred);\r
89 \r
90     seqEditOccurred = -1;\r
91 \r
92     parent.RefreshPanels();\r
93     repaint();\r
94 \r
95   }\r
96 \r
97   public void doMousePressed(MouseEvent evt) {\r
98     parent.alignFrame.addHistoryItem("sequence edit");\r
99     int seq;\r
100     int res;\r
101 \r
102     int x = evt.getX();\r
103     int y = evt.getY();\r
104 \r
105     res = x/av.getCharWidth() + av.getStartRes();\r
106     seq = y/av.getCharHeight() + av.getStartSeq();\r
107 \r
108     if (seq < av.getAlignment().getHeight() && res < av.getAlignment().getSequenceAt(seq).getLength())\r
109     {\r
110       //char resstr = align.getSequenceAt(seq).getSequence().charAt(res);\r
111       // Find the residue's position in the sequence (res is the position\r
112       // in the alignment\r
113 \r
114       startseq = seq;\r
115 \r
116       if (startseq == (av.getAlignment().getHeight()-1)) {\r
117         padseq = 1;\r
118       } else {\r
119         padseq = 1;\r
120       }\r
121 \r
122       startres = res;\r
123       lastres = res;\r
124 \r
125       } else {\r
126       startseq = -1;\r
127       startres = -1;\r
128       lastres = -1;\r
129     }\r
130 \r
131     return;\r
132   }\r
133 \r
134   public void doMouseMoved(MouseEvent evt)\r
135   {\r
136     int res=0, seq=0;\r
137     int x = evt.getX();\r
138     int y = evt.getY();\r
139     if(av.wrapAlignment)\r
140     {\r
141       y -= 2*av.charHeight;\r
142       int chunkHeight = (av.getAlignment().getHeight()+2)*av.charHeight;\r
143 \r
144 \r
145       res =   (int)((y/chunkHeight)*(getWidth()/av.charWidth)) +  x/av.getCharWidth() + av.getStartRes();\r
146 \r
147       y %= chunkHeight;\r
148       seq =     y / av.getCharHeight() + av.getStartSeq();\r
149 \r
150       //   chunkHeight =  (da.getHeight() + 2)*charHeight;\r
151       //  startx += chunkWidth;\r
152     }\r
153     else\r
154     {\r
155       res = x / av.getCharWidth()  + av.getStartRes();\r
156       seq = y / av.getCharHeight() + av.getStartSeq();\r
157     }\r
158 \r
159 \r
160     if(seq>=av.getAlignment().getHeight())\r
161       return;\r
162 \r
163     Object obj = ResidueProperties.aa2Triplet.get( av.getAlignment().getSequenceAt(seq).getCharAt(res)+"" ) ;\r
164     String aa = "";\r
165     if(obj!=null)\r
166          aa = obj.toString();\r
167 \r
168     StringBuffer text = new StringBuffer("Sequence " +(seq+1)+" ID: "+av.getAlignment().getSequenceAt(seq).getName());\r
169     if(aa!="")\r
170       text.append("  Residue: "+aa+" ("+  av.getAlignment().getSequenceAt(seq).findPosition(res)+")");\r
171 \r
172     parent.alignFrame.statusBar.setText(text.toString());\r
173 \r
174   }\r
175 \r
176   public void doMouseDragged(MouseEvent evt) {\r
177     // If we're dragging we're editing\r
178     editFlag = true;\r
179     int x = evt.getX();\r
180 \r
181     int res = x/av.getCharWidth() + av.getStartRes();\r
182     if (res < 0) {res = 0;}\r
183 \r
184     if (res  != lastres) {\r
185       if (startseq != -1) {\r
186 \r
187         // Group editing\r
188         if (av.getGroupEdit()) {\r
189           SequenceGroup sg = av.getAlignment().findGroup(startseq);\r
190 \r
191           if(sg!=null)\r
192           if (res < av.getAlignment().getWidth() && res < lastres)\r
193           {\r
194             boolean flag = false;\r
195             for (int i= 0 ; i < sg.getSize(); i++)\r
196             {\r
197               SequenceI s = (SequenceI)sg.getSequenceAt(i);\r
198               for (int j=lastres-1; j >= res; j--)\r
199               {\r
200                 if (!flag)\r
201                 {\r
202                   if (s.getSequence().charAt(j)!=av.getAlignment().getGapCharacter() &&\r
203                       s.getSequence().charAt(j)==' ')\r
204                   {\r
205                     res = j+1;\r
206                     flag = true;\r
207                   }\r
208                 }\r
209               }\r
210             }\r
211           }\r
212 \r
213           if(sg!=null)\r
214           for (int i= 0 ; i < sg.getSize(); i++)\r
215           {\r
216             SequenceI s = (SequenceI)sg.getSequenceAt(i);\r
217             boolean found = false;\r
218             int sno = -1;\r
219             for (int k = 0; k < av.getAlignment().getHeight(); k++)\r
220             {\r
221               if (av.getAlignment().getSequenceAt(k) == s)\r
222               {\r
223                 found = true;\r
224                 sno = k;\r
225                 break;\r
226               }\r
227             }\r
228             if (found && sno != -1) {\r
229               if (res < av.getAlignment().getWidth() && res > lastres)\r
230               {\r
231                 for (int j = lastres; j < res; j++)\r
232                   insertChar(j,sno);\r
233 \r
234                 int index = av.getAlignment().findIndex(s);\r
235                 if (index != -1)\r
236                   drawChars(index,index+1,lastres);\r
237 \r
238 \r
239               } else if (res < av.getAlignment().getWidth() && res < lastres)\r
240               {\r
241                 for (int j = res; j < lastres; j++)\r
242                 {\r
243                   deleteChar(j,res,sno);\r
244                   startres = res;\r
245                 }\r
246                 int index = av.getAlignment().findIndex(s);\r
247                 if (index != -1)\r
248                   drawChars(index,index+1,res);\r
249 \r
250               }\r
251             }\r
252 \r
253           }\r
254           lastres = res;\r
255         } else {\r
256 \r
257 \r
258           if (res < av.getAlignment().getWidth() && res > lastres) {\r
259             // dragging to the right\r
260             for (int j = lastres; j < res; j++)\r
261               insertChar(j,startseq);\r
262 \r
263             drawChars(startseq,startseq+1,lastres);\r
264 \r
265           } else if (res < av.getAlignment().getWidth() && res < lastres)\r
266           {\r
267 \r
268             // dragging to the left\r
269             for (int j = res; j < lastres; j++) {\r
270               deleteChar(j,res,startseq);\r
271               startres = res;\r
272             }\r
273             drawChars(startseq,startseq+1,res);\r
274           }\r
275         }\r
276       }\r
277       lastres = res;\r
278     }\r
279 \r
280     repaint();\r
281     return;\r
282   }\r
283 \r
284   public void drawChars(int seqstart, int seqend, int start) {\r
285     seqCanvas.drawPanel(seqCanvas.gg, start,av.getEndRes(),seqstart,seqend,av.getStartRes(),av.getStartSeq(),0);\r
286     repaint();\r
287   }\r
288 \r
289   public void insertChar(int j, int seq)\r
290   {\r
291     av.getAlignment().getSequenceAt(seq).insertCharAt(j, av.getGapCharacter());\r
292     seqEditOccurred=seq;\r
293   }\r
294 \r
295   public void deleteChar(int j, int res, int seq)\r
296   {\r
297 \r
298     if (av.getAlignment().getSequenceAt(seq).getSequence().charAt(j)=='.' ||\r
299         av.getAlignment().getSequenceAt(seq).getSequence().charAt(j)=='-' ||\r
300         av.getAlignment().getSequenceAt(seq).getSequence().charAt(j)==' ' )\r
301     {\r
302         av.getAlignment().getSequenceAt(seq).deleteCharAt(j);\r
303     }\r
304 \r
305     av.getAlignment().getWidth();\r
306     repaint();\r
307     seqEditOccurred=seq;\r
308   }\r
309 \r
310 \r
311   void updateConservation(int i)\r
312   {\r
313   /*  Alignment al = (Alignment) av.getAlignment();\r
314     SequenceGroup sg = av.alignment.findGroup( al.getSequenceAt(i));\r
315     if(sg==null || !(sg.cs instanceof ConservationColourScheme))\r
316       return;\r
317 \r
318     Conservation c = sg.getConservation();\r
319 \r
320     c = new Conservation("All", al.cons,\r
321                          ResidueProperties.propHash, 3, sg.sequences, 0,\r
322                          al.getWidth());\r
323     c.calculate();\r
324     c.verdict(false, 100);\r
325     sg.setConservation(c);\r
326     ConservationColourScheme ccs = (ConservationColourScheme)sg.cs;\r
327     ccs.conserve = c;*/\r
328   }\r
329 \r
330   int oldSeq = -1;\r
331 \r
332   public void doMousePressedDefineMode(MouseEvent evt)\r
333   {\r
334     int res = evt.getX()/av.getCharWidth() + av.getStartRes();\r
335     int seq = evt.getY()/av.getCharHeight() + av.getStartSeq();\r
336     oldSeq = seq;\r
337 \r
338     stretchGroup = av.getRubberbandGroup();\r
339 \r
340     if(stretchGroup == null)\r
341         stretchGroup = av.alignment.findGroup((Sequence)av.getAlignment().getSequenceAt(seq));\r
342 \r
343     else if(!stretchGroup.sequences.contains((Sequence)av.getAlignment().getSequenceAt(seq))\r
344             || stretchGroup.getStartRes()>res\r
345             || stretchGroup.getEndRes()<res)\r
346      {\r
347        stretchGroup = null;\r
348      }\r
349 \r
350     if(stretchGroup==null)\r
351     {\r
352       // define a new group here\r
353       SequenceGroup sg = new SequenceGroup();\r
354       sg.setStartRes(res);\r
355       sg.setEndRes(res);\r
356       sg.addSequence( (Sequence)av.getAlignment().getSequenceAt(seq) );\r
357       av.setRubberbandGroup( sg );\r
358       stretchGroup = sg;\r
359     }\r
360     else if( javax.swing.SwingUtilities.isRightMouseButton(evt))\r
361     {\r
362         jalview.gui.PopupMenu pop = new jalview.gui.PopupMenu( av , this);\r
363         pop.show(this, evt.getX(), evt.getY());\r
364 \r
365     // edit the properties of existing group\r
366     }\r
367 \r
368     if(stretchGroup!=null && stretchGroup.getEndRes()==res)\r
369       // Edit end res position of selected group\r
370       changeEndRes = true;\r
371 \r
372    else if(stretchGroup!=null && stretchGroup.getStartRes()==res)\r
373       // Edit end res position of selected group\r
374       changeStartRes = true;\r
375 \r
376 \r
377     seqCanvas.paintFlag = true;\r
378     repaint();\r
379 \r
380 \r
381   }\r
382 \r
383   boolean changeEndSeq = false;\r
384   boolean changeStartSeq = false;\r
385   boolean changeEndRes = false;\r
386   boolean changeStartRes = false;\r
387   SequenceGroup stretchGroup = null;\r
388 \r
389   public void doMouseReleasedDefineMode(MouseEvent evt)\r
390   {\r
391     changeEndRes = false;\r
392     changeStartRes = false;\r
393     stretchGroup = null;\r
394   }\r
395 \r
396 \r
397   boolean remove = false;\r
398   public void doMouseDraggedDefineMode(MouseEvent evt)\r
399   {\r
400     int res = evt.getX()/av.getCharWidth() + av.getStartRes();\r
401     int y = evt.getY()/av.getCharHeight() + av.getStartSeq();\r
402 \r
403 \r
404     if(stretchGroup.getEndRes()==res)\r
405       // Edit end res position of selected group\r
406       changeEndRes = true;\r
407 \r
408     else if(stretchGroup.getStartRes()==res)\r
409       // Edit end res position of selected group\r
410       changeStartRes = true;\r
411 \r
412 \r
413     if(res<av.getStartRes())\r
414       res = av.getStartRes();\r
415     else if(res>av.getEndRes())\r
416       res = av.getEndRes();\r
417 \r
418     if(changeEndRes)\r
419     {\r
420       if(res>stretchGroup.getStartRes()-1)\r
421         stretchGroup.setEndRes( res );\r
422     }\r
423     else if(changeStartRes)\r
424     {\r
425       if(res<stretchGroup.getEndRes()+1)\r
426         stretchGroup.setStartRes( res );\r
427     }\r
428 \r
429 \r
430     int dragDirection = 0;\r
431     if (y > oldSeq)\r
432       dragDirection = 1;\r
433     else if (y < oldSeq)\r
434       dragDirection = -1;\r
435 \r
436     while (y != oldSeq)\r
437     {\r
438       // This routine ensures we don't skip any sequences, as the\r
439       // selection is quite slow.\r
440       Sequence seq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);\r
441 \r
442       oldSeq += dragDirection;\r
443       Sequence nextSeq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);\r
444 \r
445       if (stretchGroup.sequences.contains(nextSeq))\r
446       {\r
447         stretchGroup.deleteSequence(seq);\r
448         stretchGroup.deleteSequence(nextSeq);\r
449       }\r
450       else\r
451       {\r
452         stretchGroup.addSequence(seq);\r
453         stretchGroup.addSequence(nextSeq);\r
454       }\r
455     }\r
456     oldSeq = y;\r
457 \r
458     seqCanvas.paintFlag = true;\r
459     repaint();\r
460   }\r
461 \r
462 \r
463 }\r
464 \r
465 \r
466 \r
467 \r