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