Clover icon

Coverage Report

  1. Project Clover database Thu Nov 27 2025 16:51:35 GMT
  2. Package jalview.appletgui

File AnnotationLabels.java

 

Coverage histogram

../../img/srcFileCovDistChart0.png
60% of files have more coverage

Code metrics

132
308
27
1
925
714
111
0.36
11.41
27
4.11

Classes

Class Line # Actions
AnnotationLabels 56 308 111
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

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