3e8166415416344c27ede87174735efa1b1376d7
[jalview.git] / src / jalview / appletgui / AnnotationLabels.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 The Jalview Authors
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
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.appletgui;
22
23 import java.util.*;
24 import java.awt.*;
25 import java.awt.event.*;
26
27 import jalview.datamodel.*;
28 import jalview.util.MessageManager;
29 import jalview.util.ParseHtmlBodyAndLinks;
30
31 public class AnnotationLabels extends Panel implements ActionListener,
32         MouseListener, MouseMotionListener
33 {
34   Image image;
35
36   boolean active = false;
37
38   AlignmentPanel ap;
39
40   AlignViewport av;
41
42   boolean resizing = false;
43
44   int oldY, mouseX;
45
46   static String ADDNEW = "Add New Row";
47
48   static String EDITNAME = "Edit Label/Description";
49
50   static String HIDE = "Hide This Row";
51
52   static String SHOWALL = "Show All Hidden Rows";
53
54   static String OUTPUT_TEXT = "Show Values In Textbox";
55
56   static String COPYCONS_SEQ = "Copy Consensus Sequence";
57
58   int scrollOffset = 0;
59
60   int selectedRow = -1;
61
62   Tooltip tooltip;
63
64   private boolean hasHiddenRows;
65
66   public AnnotationLabels(AlignmentPanel ap)
67   {
68     this.ap = ap;
69     this.av = ap.av;
70     setLayout(null);
71
72     /**
73      * this retrieves the adjustable height glyph from resources. we don't use
74      * it at the moment. java.net.URL url =
75      * getClass().getResource("/images/idwidth.gif"); Image temp = null;
76      * 
77      * if (url != null) { temp =
78      * java.awt.Toolkit.getDefaultToolkit().createImage(url); }
79      * 
80      * try { MediaTracker mt = new MediaTracker(this); mt.addImage(temp, 0);
81      * mt.waitForID(0); } catch (Exception ex) { }
82      * 
83      * BufferedImage bi = new BufferedImage(temp.getHeight(this),
84      * temp.getWidth(this), BufferedImage.TYPE_INT_RGB); Graphics2D g =
85      * (Graphics2D) bi.getGraphics(); g.rotate(Math.toRadians(90));
86      * g.drawImage(temp, 0, -bi.getWidth(this), this); image = (Image) bi;
87      */
88     addMouseListener(this);
89     addMouseMotionListener(this);
90   }
91
92   public AnnotationLabels(AlignViewport av)
93   {
94     this.av = av;
95   }
96
97   public void setScrollOffset(int y, boolean repaint)
98   {
99     scrollOffset = y;
100     if (repaint)
101     {
102       repaint();
103     }
104   }
105
106   /**
107    * 
108    * @param y
109    * @return -2 if no rows are visible at all, -1 if no visible rows were
110    *         selected
111    */
112   int getSelectedRow(int y)
113   {
114     int row = -2;
115     AlignmentAnnotation[] aa = ap.av.getAlignment()
116             .getAlignmentAnnotation();
117
118     if (aa == null)
119     {
120       return row;
121     }
122     int height = 0;
123     for (int i = 0; i < aa.length; i++)
124     {
125       row = -1;
126       if (!aa[i].visible)
127       {
128         continue;
129       }
130       height += aa[i].height;
131       if (y < height)
132       {
133         row = i;
134         break;
135       }
136     }
137
138     return row;
139   }
140
141   public void actionPerformed(ActionEvent evt)
142   {
143     AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
144
145     if (evt.getActionCommand().equals(ADDNEW))
146     {
147       AlignmentAnnotation newAnnotation = new AlignmentAnnotation("", null,
148               new Annotation[ap.av.getAlignment().getWidth()]);
149
150       if (!editLabelDescription(newAnnotation))
151       {
152         return;
153       }
154
155       ap.av.getAlignment().addAnnotation(newAnnotation);
156       ap.av.getAlignment().setAnnotationIndex(newAnnotation, 0);
157     }
158     else if (evt.getActionCommand().equals(EDITNAME))
159     {
160       editLabelDescription(aa[selectedRow]);
161     }
162     else if (evt.getActionCommand().equals(HIDE))
163     {
164       aa[selectedRow].visible = false;
165     }
166     else if (evt.getActionCommand().equals(SHOWALL))
167     {
168       for (int i = 0; i < aa.length; i++)
169       {
170         aa[i].visible = (aa[i].annotations == null) ? false : true;
171       }
172     }
173     else if (evt.getActionCommand().equals(OUTPUT_TEXT))
174     {
175       CutAndPasteTransfer cap = new CutAndPasteTransfer(false,
176               ap.alignFrame);
177       Frame frame = new Frame();
178       frame.add(cap);
179       jalview.bin.JalviewLite.addFrame(frame, ap.alignFrame.getTitle()
180               + " - " + aa[selectedRow].label, 500, 100);
181       cap.setText(aa[selectedRow].toString());
182     }
183     else if (evt.getActionCommand().equals(COPYCONS_SEQ))
184     {
185       SequenceI cons = av.getConsensusSeq();
186       if (cons != null)
187       {
188         copy_annotseqtoclipboard(cons);
189       }
190
191     }
192     ap.annotationPanel.adjustPanelHeight();
193     setSize(getSize().width, ap.annotationPanel.getSize().height);
194     ap.validate();
195     ap.paintAlignment(true);
196   }
197
198   boolean editLabelDescription(AlignmentAnnotation annotation)
199   {
200     Checkbox padGaps = new Checkbox("Fill Empty Gaps With \""
201             + ap.av.getGapCharacter() + "\"", annotation.padGaps);
202
203     EditNameDialog dialog = new EditNameDialog(annotation.label,
204             annotation.description, "      Annotation Label",
205             "Annotation Description", ap.alignFrame,
206             "Edit Annotation Name / Description", 500, 180, false);
207
208     Panel empty = new Panel(new FlowLayout());
209     empty.add(padGaps);
210     dialog.add(empty);
211     dialog.pack();
212
213     dialog.setVisible(true);
214
215     if (dialog.accept)
216     {
217       annotation.label = dialog.getName();
218       annotation.description = dialog.getDescription();
219       annotation.setPadGaps(padGaps.getState(), av.getGapCharacter());
220       repaint();
221       return true;
222     }
223     else
224       return false;
225
226   }
227
228   boolean resizePanel = false;
229
230   public void mouseMoved(MouseEvent evt)
231   {
232     resizePanel = evt.getY() < 10 && evt.getX() < 14;
233     int row = getSelectedRow(evt.getY() + scrollOffset);
234
235     if (row > -1)
236     {
237       ParseHtmlBodyAndLinks phb = new ParseHtmlBodyAndLinks(
238               av.getAlignment().getAlignmentAnnotation()[row]
239                       .getDescription(true),
240               true, "\n");
241       if (tooltip == null)
242       {
243         tooltip = new Tooltip(phb.getNonHtmlContent(), this);
244       }
245       else
246       {
247         tooltip.setTip(phb.getNonHtmlContent());
248       }
249     }
250     else if (tooltip != null)
251     {
252       tooltip.setTip("");
253     }
254   }
255
256   /**
257    * curent drag position
258    */
259   MouseEvent dragEvent = null;
260
261   /**
262    * flag to indicate drag events should be ignored
263    */
264   private boolean dragCancelled = false;
265
266   /**
267    * clear any drag events in progress
268    */
269   public void cancelDrag()
270   {
271     dragEvent = null;
272     dragCancelled = true;
273   }
274
275   public void mouseDragged(MouseEvent evt)
276   {
277     if (dragCancelled)
278     {
279       return;
280     }
281     ;
282     dragEvent = evt;
283
284     if (resizePanel)
285     {
286       Dimension d = ap.annotationPanelHolder.getSize(), e = ap.annotationSpaceFillerHolder
287               .getSize(), f = ap.seqPanelHolder.getSize();
288       int dif = evt.getY() - oldY;
289
290       dif /= ap.av.charHeight;
291       dif *= ap.av.charHeight;
292
293       if ((d.height - dif) > 20 && (f.height + dif) > 20)
294       {
295         ap.annotationPanel.setSize(d.width, d.height - dif);
296         setSize(new Dimension(e.width, d.height - dif));
297         ap.annotationSpaceFillerHolder.setSize(new Dimension(e.width,
298                 d.height - dif));
299         ap.annotationPanelHolder.setSize(new Dimension(d.width, d.height
300                 - dif));
301         ap.apvscroll.setValues(ap.apvscroll.getValue(), d.height - dif, 0,
302                 av.calcPanelHeight());
303         f.height += dif;
304         ap.seqPanelHolder.setPreferredSize(f);
305         ap.setScrollValues(av.getStartRes(), av.getStartSeq());
306         ap.validate();
307         // ap.paintAlignment(true);
308         ap.addNotify();
309       }
310
311     }
312     else
313     {
314       int diff;
315       if ((diff = 6 - evt.getY()) > 0)
316       {
317         // nudge scroll up
318         ap.apvscroll.setValue(ap.apvscroll.getValue() - diff);
319         ap.adjustmentValueChanged(null);
320
321       }
322       else if ((0 < (diff = 6
323               - ap.annotationSpaceFillerHolder.getSize().height
324               + evt.getY())))
325       {
326         // nudge scroll down
327         ap.apvscroll.setValue(ap.apvscroll.getValue() + diff);
328         ap.adjustmentValueChanged(null);
329       }
330       repaint();
331     }
332   }
333
334   public void mouseClicked(MouseEvent evt)
335   {
336   }
337
338   public void mouseReleased(MouseEvent evt)
339   {
340     if (!resizePanel && !dragCancelled)
341     {
342       int start = selectedRow;
343
344       int end = getSelectedRow(evt.getY() + scrollOffset);
345
346       if (start > -1 && start != end)
347       {
348         // Swap these annotations
349         AlignmentAnnotation startAA = ap.av.getAlignment()
350                 .getAlignmentAnnotation()[start];
351         if (end == -1)
352         {
353           end = ap.av.getAlignment().getAlignmentAnnotation().length - 1;
354         }
355         AlignmentAnnotation endAA = ap.av.getAlignment()
356                 .getAlignmentAnnotation()[end];
357
358         ap.av.getAlignment().getAlignmentAnnotation()[end] = startAA;
359         ap.av.getAlignment().getAlignmentAnnotation()[start] = endAA;
360       }
361     }
362     resizePanel = false;
363     dragEvent = null;
364     dragCancelled = false;
365     repaint();
366     ap.annotationPanel.repaint();
367   }
368
369   public void mouseEntered(MouseEvent evt)
370   {
371     if (evt.getY() < 10 && evt.getX() < 14)
372     {
373       resizePanel = true;
374       repaint();
375     }
376   }
377
378   public void mouseExited(MouseEvent evt)
379   {
380     dragCancelled = false;
381
382     if (dragEvent == null)
383     {
384       resizePanel = false;
385     }
386     else
387     {
388       if (!resizePanel)
389       {
390         dragEvent = null;
391       }
392     }
393     repaint();
394   }
395
396   public void mousePressed(MouseEvent evt)
397   {
398     oldY = evt.getY();
399     if (resizePanel)
400     {
401       return;
402     }
403     dragCancelled = false;
404     // todo: move below to mouseClicked ?
405     selectedRow = getSelectedRow(evt.getY() + scrollOffset);
406
407     AlignmentAnnotation[] aa = ap.av.getAlignment()
408             .getAlignmentAnnotation();
409
410     // DETECT RIGHT MOUSE BUTTON IN AWT
411     if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
412     {
413
414       PopupMenu popup = new PopupMenu(
415               MessageManager.getString("label.annotations"));
416
417       MenuItem item = new MenuItem(ADDNEW);
418       item.addActionListener(this);
419       popup.add(item);
420       if (selectedRow < 0)
421       {
422         // this never happens at moment: - see comment on JAL-563
423         if (hasHiddenRows)
424         {
425           item = new MenuItem(SHOWALL);
426           item.addActionListener(this);
427           popup.add(item);
428         }
429         this.add(popup);
430         popup.show(this, evt.getX(), evt.getY());
431         return;
432       }
433       // add the rest if there are actually rows to show
434       item = new MenuItem(EDITNAME);
435       item.addActionListener(this);
436       popup.add(item);
437       item = new MenuItem(HIDE);
438       item.addActionListener(this);
439       popup.add(item);
440       if (hasHiddenRows)
441       {
442         item = new MenuItem(SHOWALL);
443         item.addActionListener(this);
444         popup.add(item);
445       }
446       this.add(popup);
447       item = new MenuItem(OUTPUT_TEXT);
448       item.addActionListener(this);
449       popup.add(item);
450       if (selectedRow < aa.length)
451       {
452         if (aa[selectedRow].autoCalculated)
453         {
454           if (aa[selectedRow].label.indexOf("Consensus") > -1)
455           {
456             popup.addSeparator();
457             final CheckboxMenuItem cbmi = new CheckboxMenuItem(
458                     MessageManager.getString("label.ignore_gaps_consensus"),
459                     (aa[selectedRow].groupRef != null) ? aa[selectedRow].groupRef
460                             .getIgnoreGapsConsensus() : ap.av
461                             .getIgnoreGapsConsensus());
462             final AlignmentAnnotation aaa = aa[selectedRow];
463             cbmi.addItemListener(new ItemListener()
464             {
465               public void itemStateChanged(ItemEvent e)
466               {
467                 if (aaa.groupRef != null)
468                 {
469                   // TODO: pass on reference to ap so the view can be updated.
470                   aaa.groupRef.setIgnoreGapsConsensus(cbmi.getState());
471                 }
472                 else
473                 {
474                   ap.av.setIgnoreGapsConsensus(cbmi.getState());
475                 }
476                 ap.paintAlignment(true);
477               }
478             });
479             popup.add(cbmi);
480             if (aaa.groupRef != null)
481             {
482               final CheckboxMenuItem chist = new CheckboxMenuItem(
483                       MessageManager.getString("label.show_group_histogram"),
484                       aa[selectedRow].groupRef.isShowConsensusHistogram());
485               chist.addItemListener(new ItemListener()
486               {
487                 public void itemStateChanged(ItemEvent e)
488                 {
489                   // TODO: pass on reference
490                   // to ap
491                   // so the
492                   // view
493                   // can be
494                   // updated.
495                   aaa.groupRef.setShowConsensusHistogram(chist.getState());
496                   ap.repaint();
497                   // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
498                 }
499               });
500               popup.add(chist);
501               final CheckboxMenuItem cprofl = new CheckboxMenuItem(
502                       MessageManager.getString("label.show_group_logo"),
503                       aa[selectedRow].groupRef.isShowSequenceLogo());
504               cprofl.addItemListener(new ItemListener()
505               {
506                 public void itemStateChanged(ItemEvent e)
507                 {
508                   // TODO: pass on reference
509                   // to ap
510                   // so the
511                   // view
512                   // can be
513                   // updated.
514                   aaa.groupRef.setshowSequenceLogo(cprofl.getState());
515                   ap.repaint();
516                   // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
517                 }
518               });
519
520               popup.add(cprofl);
521               final CheckboxMenuItem cprofn = new CheckboxMenuItem(
522                       MessageManager.getString("label.normalise_group_logo"),
523                       aa[selectedRow].groupRef.isNormaliseSequenceLogo());
524               cprofn.addItemListener(new ItemListener()
525               {
526                 public void itemStateChanged(ItemEvent e)
527                 {
528                   // TODO: pass on reference
529                   // to ap
530                   // so the
531                   // view
532                   // can be
533                   // updated.
534                   aaa.groupRef.setshowSequenceLogo(true);
535                   aaa.groupRef.setNormaliseSequenceLogo(cprofn.getState());
536                   ap.repaint();
537                   // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
538                 }
539               });
540               popup.add(cprofn);
541             }
542             else
543             {
544               final CheckboxMenuItem chist = new CheckboxMenuItem(
545                       MessageManager.getString("label.show_histogram"), av.isShowConsensusHistogram());
546               chist.addItemListener(new ItemListener()
547               {
548                 public void itemStateChanged(ItemEvent e)
549                 {
550                   // TODO: pass on reference
551                   // to ap
552                   // so the
553                   // view
554                   // can be
555                   // updated.
556                   av.setShowConsensusHistogram(chist.getState());
557                   ap.alignFrame.showConsensusHistogram.setState(chist
558                           .getState()); // TODO: implement
559                                         // ap.updateGUI()/alignFrame.updateGUI
560                                         // for applet
561                   ap.repaint();
562                   // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
563                 }
564               });
565               popup.add(chist);
566               final CheckboxMenuItem cprof = new CheckboxMenuItem(
567                       MessageManager.getString("label.show_logo"), av.isShowSequenceLogo());
568               cprof.addItemListener(new ItemListener()
569               {
570                 public void itemStateChanged(ItemEvent e)
571                 {
572                   // TODO: pass on reference
573                   // to ap
574                   // so the
575                   // view
576                   // can be
577                   // updated.
578                   av.setShowSequenceLogo(cprof.getState());
579                   ap.alignFrame.showSequenceLogo.setState(cprof.getState()); // TODO:
580                                                                              // implement
581                                                                              // ap.updateGUI()/alignFrame.updateGUI
582                                                                              // for
583                                                                              // applet
584                   ap.repaint();
585                   // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
586                 }
587               });
588               popup.add(cprof);
589               final CheckboxMenuItem cprofn = new CheckboxMenuItem(
590                       MessageManager.getString("label.normalise_logo"), av.isNormaliseSequenceLogo());
591               cprofn.addItemListener(new ItemListener()
592               {
593                 public void itemStateChanged(ItemEvent e)
594                 {
595                   // TODO: pass on reference
596                   // to ap
597                   // so the
598                   // view
599                   // can be
600                   // updated.
601                   av.setShowSequenceLogo(true);
602                   ap.alignFrame.normSequenceLogo.setState(cprofn.getState()); // TODO:
603                                                                               // implement
604                                                                               // ap.updateGUI()/alignFrame.updateGUI
605                                                                               // for
606                                                                               // applet
607                   av.setNormaliseSequenceLogo(cprofn.getState());
608                   ap.repaint();
609                   // ap.annotationPanel.paint(ap.annotationPanel.getGraphics());
610                 }
611               });
612               popup.add(cprofn);
613             }
614
615             item = new MenuItem(COPYCONS_SEQ);
616             item.addActionListener(this);
617             popup.add(item);
618           }
619         }
620       }
621       popup.show(this, evt.getX(), evt.getY());
622     }
623     else
624     {
625       // selection action.
626       if (selectedRow > -1 && selectedRow < aa.length)
627       {
628         if (aa[selectedRow].groupRef != null)
629         {
630           if (evt.getClickCount() >= 2)
631           {
632             // todo: make the ap scroll to the selection - not necessary, first
633             // click highlights/scrolls, second selects
634             ap.seqPanel.ap.idPanel.highlightSearchResults(null);
635             ap.av.setSelectionGroup(// new SequenceGroup(
636             aa[selectedRow].groupRef); // );
637             ap.av.sendSelection();
638             ap.paintAlignment(false);
639             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
640           }
641           else
642           {
643             ap.seqPanel.ap.idPanel
644                     .highlightSearchResults(aa[selectedRow].groupRef
645                             .getSequences(null));
646           }
647           return;
648         }
649         else if (aa[selectedRow].sequenceRef != null)
650         {
651           if (evt.getClickCount() == 1)
652           {
653             ap.seqPanel.ap.idPanel.highlightSearchResults(Arrays
654                     .asList(new SequenceI[]
655                     { aa[selectedRow].sequenceRef }));
656           }
657           else if (evt.getClickCount() >= 2)
658           {
659             ap.seqPanel.ap.idPanel.highlightSearchResults(null);
660             SequenceGroup sg = ap.av.getSelectionGroup();
661             if (sg!=null)
662             {
663               // we make a copy rather than edit the current selection if no modifiers pressed
664               // see Enhancement JAL-1557
665               if (!(evt.isControlDown() || evt.isShiftDown()))
666               {
667                 sg = new SequenceGroup(sg);
668                 sg.clear();
669                 sg.addSequence(aa[selectedRow].sequenceRef, false);
670               } else {
671                 if (evt.isControlDown())
672                 {
673                   sg.addOrRemove(aa[selectedRow].sequenceRef, true);
674                 } else {
675                   // notionally, we should also add intermediate sequences from last added sequence ?
676                   sg.addSequence(aa[selectedRow].sequenceRef, true);
677                 }
678               }
679             } else {
680               sg = new SequenceGroup();
681               sg.setStartRes(0);
682               sg.setEndRes(ap.av.getAlignment().getWidth()-1);
683               sg.addSequence(aa[selectedRow].sequenceRef, false);
684             }
685             ap.av.setSelectionGroup(sg);
686             ap.paintAlignment(false);
687             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
688             ap.av.sendSelection();
689           }
690
691         }
692       }
693
694     }
695   }
696
697   /**
698    * DOCUMENT ME!
699    * 
700    * @param e
701    *          DOCUMENT ME!
702    */
703   protected void copy_annotseqtoclipboard(SequenceI sq)
704   {
705     if (sq == null || sq.getLength() < 1)
706     {
707       return;
708     }
709     jalview.appletgui.AlignFrame.copiedSequences = new StringBuffer();
710     jalview.appletgui.AlignFrame.copiedSequences.append(sq.getName() + "\t"
711             + sq.getStart() + "\t" + sq.getEnd() + "\t"
712             + sq.getSequenceAsString() + "\n");
713     if (av.hasHiddenColumns())
714     {
715       jalview.appletgui.AlignFrame.copiedHiddenColumns = new Vector();
716       for (int i = 0; i < av.getColumnSelection().getHiddenColumns().size(); i++)
717       {
718         int[] region = (int[]) av.getColumnSelection().getHiddenColumns()
719                 .elementAt(i);
720
721         jalview.appletgui.AlignFrame.copiedHiddenColumns
722                 .addElement(new int[]
723                 { region[0], region[1] });
724       }
725     }
726   }
727
728   public void update(Graphics g)
729   {
730     paint(g);
731   }
732
733   public void paint(Graphics g)
734   {
735     int w = getSize().width;
736     int h = getSize().height;
737     if (image == null || w != image.getWidth(this)
738             || h != image.getHeight(this))
739     {
740       image = createImage(w, ap.annotationPanel.getSize().height);
741     }
742
743     drawComponent(image.getGraphics(), w);
744     g.drawImage(image, 0, 0, this);
745   }
746
747   public void drawComponent(Graphics g, int width)
748   {
749     g.setFont(av.getFont());
750     FontMetrics fm = g.getFontMetrics(av.getFont());
751     g.setColor(Color.white);
752     g.fillRect(0, 0, getSize().width, getSize().height);
753
754     g.translate(0, -scrollOffset);
755     g.setColor(Color.black);
756
757     AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
758     int y = 0, fy = g.getFont().getSize();
759     int x = 0, offset;
760
761     if (aa != null)
762     {
763       hasHiddenRows = false;
764       for (int i = 0; i < aa.length; i++)
765       {
766         if (!aa[i].visible)
767         {
768           hasHiddenRows = true;
769           continue;
770         }
771
772         x = width - fm.stringWidth(aa[i].label) - 3;
773
774         y += aa[i].height;
775         offset = -(aa[i].height - fy) / 2;
776
777         g.drawString(aa[i].label, x, y + offset);
778       }
779     }
780     g.translate(0, +scrollOffset);
781     if (resizePanel)
782     {
783       g.setColor(Color.red);
784       g.setPaintMode();
785       g.drawLine(2, 8, 5, 2);
786       g.drawLine(5, 2, 8, 8);
787     }
788     else if (!dragCancelled && dragEvent != null && aa != null)
789     {
790       g.setColor(Color.lightGray);
791       g.drawString(aa[selectedRow].label, dragEvent.getX(),
792               dragEvent.getY());
793     }
794
795     if (!av.wrapAlignment && ((aa == null) || (aa.length < 1)))
796     {
797       g.setColor(Color.black);
798       g.drawString(MessageManager.getString("label.right_click"), 2, 8);
799       g.drawString(MessageManager.getString("label.to_add_annotation"), 2,
800               18);
801     }
802   }
803 }