javascript callback for selection, mousover, and functions for selection and highligh...
[jalview.git] / src / jalview / appletgui / AnnotationLabels.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
3  * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  * 
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.appletgui;
19
20 import java.util.*;
21
22 import java.awt.*;
23 import java.awt.event.*;
24
25 import jalview.datamodel.*;
26
27 public class AnnotationLabels extends Panel implements ActionListener,
28         MouseListener, MouseMotionListener
29 {
30   Image image;
31
32   boolean active = false;
33
34   AlignmentPanel ap;
35
36   AlignViewport av;
37
38   boolean resizing = false;
39
40   int oldY, mouseX;
41
42   static String ADDNEW = "Add New Row";
43
44   static String EDITNAME = "Edit Label/Description";
45
46   static String HIDE = "Hide This Row";
47
48   static String SHOWALL = "Show All Hidden Rows";
49
50   static String OUTPUT_TEXT = "Show Values In Textbox";
51
52   static String COPYCONS_SEQ = "Copy Consensus Sequence";
53
54   int scrollOffset = 0;
55
56   int selectedRow = -1;
57
58   Tooltip tooltip;
59
60   private boolean hasHiddenRows;
61
62   public AnnotationLabels(AlignmentPanel ap)
63   {
64     this.ap = ap;
65     this.av = ap.av;
66     setLayout(null);
67     addMouseListener(this);
68     addMouseMotionListener(this);
69   }
70
71   public AnnotationLabels(AlignViewport av)
72   {
73     this.av = av;
74   }
75
76   public void setScrollOffset(int y)
77   {
78     scrollOffset = y;
79     repaint();
80   }
81
82   /**
83    * 
84    * @param y
85    * @return -2 if no rows are visible at all, -1 if no visible rows were
86    *         selected
87    */
88   int getSelectedRow(int y)
89   {
90     int row = -2;
91     AlignmentAnnotation[] aa = ap.av.alignment.getAlignmentAnnotation();
92
93     if (aa == null)
94     {
95       return row;
96     }
97     int height = 0;
98     for (int i = 0; i < aa.length; i++)
99     {
100       row = -1;
101       if (!aa[i].visible)
102       {
103         continue;
104       }
105       height += aa[i].height;
106       if (y < height)
107       {
108         row = i;
109         break;
110       }
111     }
112
113     return row;
114   }
115
116   public void actionPerformed(ActionEvent evt)
117   {
118     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();
119
120     if (evt.getActionCommand().equals(ADDNEW))
121     {
122       AlignmentAnnotation newAnnotation = new AlignmentAnnotation("", null,
123               new Annotation[ap.av.alignment.getWidth()]);
124
125       if (!editLabelDescription(newAnnotation))
126       {
127         return;
128       }
129
130       ap.av.alignment.addAnnotation(newAnnotation);
131       ap.av.alignment.setAnnotationIndex(newAnnotation, 0);
132     }
133     else if (evt.getActionCommand().equals(EDITNAME))
134     {
135       editLabelDescription(aa[selectedRow]);
136     }
137     else if (evt.getActionCommand().equals(HIDE))
138     {
139       aa[selectedRow].visible = false;
140     }
141     else if (evt.getActionCommand().equals(SHOWALL))
142     {
143       for (int i = 0; i < aa.length; i++)
144       {
145         aa[i].visible = (aa[i].annotations == null) ? false : true;
146       }
147     }
148     else if (evt.getActionCommand().equals(OUTPUT_TEXT))
149     {
150       CutAndPasteTransfer cap = new CutAndPasteTransfer(false,
151               ap.alignFrame);
152       Frame frame = new Frame();
153       frame.add(cap);
154       jalview.bin.JalviewLite.addFrame(frame, ap.alignFrame.getTitle()
155               + " - " + aa[selectedRow].label, 500, 100);
156       cap.setText(aa[selectedRow].toString());
157     }
158     else if (evt.getActionCommand().equals(COPYCONS_SEQ))
159     {
160       SequenceI cons = av.getConsensusSeq();
161       if (cons != null)
162       {
163         copy_annotseqtoclipboard(cons);
164       }
165
166     }
167     ap.annotationPanel.adjustPanelHeight();
168     setSize(getSize().width, ap.annotationPanel.getSize().height);
169     ap.validate();
170     ap.paintAlignment(true);
171   }
172
173   boolean editLabelDescription(AlignmentAnnotation annotation)
174   {
175     Checkbox padGaps = new Checkbox("Fill Empty Gaps With \""
176             + ap.av.getGapCharacter() + "\"", annotation.padGaps);
177
178     EditNameDialog dialog = new EditNameDialog(annotation.label,
179             annotation.description, "      Annotation Label",
180             "Annotation Description", ap.alignFrame,
181             "Edit Annotation Name / Description", 500, 180, false);
182
183     Panel empty = new Panel(new FlowLayout());
184     empty.add(padGaps);
185     dialog.add(empty);
186     dialog.pack();
187
188     dialog.setVisible(true);
189
190     if (dialog.accept)
191     {
192       annotation.label = dialog.getName();
193       annotation.description = dialog.getDescription();
194       annotation.setPadGaps(padGaps.getState(), av.getGapCharacter());
195       repaint();
196       return true;
197     }
198     else
199       return false;
200
201   }
202
203   public void mouseMoved(MouseEvent evt)
204   {
205     int row = getSelectedRow(evt.getY() - scrollOffset);
206
207     if (row > -1)
208     {
209       if (tooltip == null)
210       {
211         tooltip = new Tooltip(
212                 ap.av.alignment.getAlignmentAnnotation()[row]
213                         .getDescription(true),
214                 this);
215       }
216       else
217       {
218         tooltip.setTip(ap.av.alignment.getAlignmentAnnotation()[row]
219                 .getDescription(true));
220       }
221     }
222     else if (tooltip != null)
223     {
224       tooltip.setTip("");
225     }
226
227   }
228
229   public void mouseDragged(MouseEvent evt)
230   {
231   }
232
233   public void mouseClicked(MouseEvent evt)
234   {
235   }
236
237   public void mouseReleased(MouseEvent evt)
238   {
239   }
240
241   public void mouseEntered(MouseEvent evt)
242   {
243   }
244
245   public void mouseExited(MouseEvent evt)
246   {
247   }
248
249   public void mousePressed(MouseEvent evt)
250   {
251     selectedRow = getSelectedRow(evt.getY() - scrollOffset);
252     AlignmentAnnotation[] aa = ap.av.alignment.getAlignmentAnnotation();
253
254     // DETECT RIGHT MOUSE BUTTON IN AWT
255     if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
256     {
257
258
259     PopupMenu popup = new PopupMenu("Annotations");
260
261     MenuItem item = new MenuItem(ADDNEW);
262     item.addActionListener(this);
263     popup.add(item);
264     if (selectedRow < 0)
265     {
266       // this never happens at moment: - see comment on JAL-563
267       if (hasHiddenRows)
268       {
269         item = new MenuItem(SHOWALL);
270         item.addActionListener(this);
271         popup.add(item);
272       }
273       this.add(popup);
274       popup.show(this, evt.getX(), evt.getY());
275       return;
276     }
277     // add the rest if there are actually rows to show
278     item = new MenuItem(EDITNAME);
279     item.addActionListener(this);
280     popup.add(item);
281     item = new MenuItem(HIDE);
282     item.addActionListener(this);
283     popup.add(item);
284     if (hasHiddenRows)
285     {
286       item = new MenuItem(SHOWALL);
287       item.addActionListener(this);
288       popup.add(item);
289     }
290     this.add(popup);
291     item = new MenuItem(OUTPUT_TEXT);
292     item.addActionListener(this);
293     popup.add(item);
294
295     if (aa[selectedRow] == ap.av.consensus)
296     {
297       popup.addSeparator();
298       final CheckboxMenuItem cbmi = new CheckboxMenuItem(
299               "Ignore Gaps In Consensus", ap.av.getIgnoreGapsConsensus());
300
301       cbmi.addItemListener(new ItemListener()
302       {
303         public void itemStateChanged(ItemEvent e)
304         {
305           ap.av.setIgnoreGapsConsensus(cbmi.getState());
306           ap.paintAlignment(true);
307         }
308       });
309       popup.add(cbmi);
310       item = new MenuItem(COPYCONS_SEQ);
311       item.addActionListener(this);
312       popup.add(item);
313     }
314
315     popup.show(this, evt.getX(), evt.getY());
316     } else {
317       // selection action.
318       if (selectedRow > -1 && selectedRow < aa.length)
319       {
320         if (aa[selectedRow].groupRef != null)
321         {
322           if (evt.getClickCount() >= 2)
323           {
324             // todo: make the ap scroll to the selection - not necessary, first click highlights/scrolls, second selects
325             ap.seqPanel.ap.idPanel.highlightSearchResults(null);
326             ap.av.setSelectionGroup(// new SequenceGroup(
327             aa[selectedRow].groupRef); // );
328             ap.av.sendSelection();
329             ap.paintAlignment(false);
330             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
331           }
332           else
333           {
334             ap.seqPanel.ap.idPanel
335                     .highlightSearchResults(aa[selectedRow].groupRef
336                             .getSequences(null));
337           }
338           return;
339         }
340         else if (aa[selectedRow].sequenceRef != null)
341         {
342           Vector sr = new Vector();
343           sr.addElement(aa[selectedRow].sequenceRef);
344           if (evt.getClickCount() == 1)
345           {
346             ap.seqPanel.ap.idPanel.highlightSearchResults(sr);
347           }
348           else if (evt.getClickCount() >= 2)
349           {
350             ap.seqPanel.ap.idPanel.highlightSearchResults(null);
351             SequenceGroup sg = new SequenceGroup();
352             sg.addSequence(aa[selectedRow].sequenceRef, false);
353             ap.av.setSelectionGroup(sg);
354             ap.paintAlignment(false);
355             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
356             ap.av.sendSelection();
357           }
358
359         }
360       }
361
362     }
363   }
364
365   /**
366    * DOCUMENT ME!
367    * 
368    * @param e
369    *          DOCUMENT ME!
370    */
371   protected void copy_annotseqtoclipboard(SequenceI sq)
372   {
373     if (sq == null || sq.getLength() < 1)
374     {
375       return;
376     }
377     jalview.appletgui.AlignFrame.copiedSequences = new StringBuffer();
378     jalview.appletgui.AlignFrame.copiedSequences.append(sq.getName() + "\t"
379             + sq.getStart() + "\t" + sq.getEnd() + "\t"
380             + sq.getSequenceAsString() + "\n");
381     if (av.hasHiddenColumns)
382     {
383       jalview.appletgui.AlignFrame.copiedHiddenColumns = new Vector();
384       for (int i = 0; i < av.getColumnSelection().getHiddenColumns().size(); i++)
385       {
386         int[] region = (int[]) av.getColumnSelection().getHiddenColumns()
387                 .elementAt(i);
388
389         jalview.appletgui.AlignFrame.copiedHiddenColumns
390                 .addElement(new int[]
391                 { region[0], region[1] });
392       }
393     }
394   }
395
396   public void update(Graphics g)
397   {
398     paint(g);
399   }
400
401   public void paint(Graphics g)
402   {
403     int w = getSize().width;
404     if (image == null || w != image.getWidth(this))
405     {
406       image = createImage(w, ap.annotationPanel.getSize().height);
407     }
408
409     drawComponent(image.getGraphics(), w);
410     g.drawImage(image, 0, 0, this);
411   }
412
413   public void drawComponent(Graphics g, int width)
414   {
415     g.setFont(av.getFont());
416     FontMetrics fm = g.getFontMetrics(av.getFont());
417     g.setColor(Color.white);
418     g.fillRect(0, 0, getSize().width, getSize().height);
419
420     g.translate(0, scrollOffset);
421     g.setColor(Color.black);
422
423     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();
424     int y = 0, fy = g.getFont().getSize();
425     int x = 0, offset;
426
427     if (aa != null)
428     {
429       hasHiddenRows = false;
430       for (int i = 0; i < aa.length; i++)
431       {
432         if (!aa[i].visible)
433         {
434           hasHiddenRows = true;
435           continue;
436         }
437
438         x = width - fm.stringWidth(aa[i].label) - 3;
439
440         y += aa[i].height;
441         offset = -(aa[i].height - fy) / 2;
442
443         g.drawString(aa[i].label, x, y + offset);
444       }
445     }
446   }
447
448 }