Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
PopupMenu | 97 | 782 | 231 |
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.gui; | |
22 | ||
23 | import java.awt.BorderLayout; | |
24 | import java.awt.Color; | |
25 | import java.awt.event.ActionEvent; | |
26 | import java.awt.event.ActionListener; | |
27 | import java.util.ArrayList; | |
28 | import java.util.Arrays; | |
29 | import java.util.BitSet; | |
30 | import java.util.Collection; | |
31 | import java.util.Collections; | |
32 | import java.util.Hashtable; | |
33 | import java.util.LinkedHashMap; | |
34 | import java.util.List; | |
35 | import java.util.Locale; | |
36 | import java.util.Map; | |
37 | import java.util.Objects; | |
38 | import java.util.SortedMap; | |
39 | import java.util.TreeMap; | |
40 | import java.util.Vector; | |
41 | ||
42 | import javax.swing.ButtonGroup; | |
43 | import javax.swing.JCheckBoxMenuItem; | |
44 | import javax.swing.JInternalFrame; | |
45 | import javax.swing.JLabel; | |
46 | import javax.swing.JMenu; | |
47 | import javax.swing.JMenuItem; | |
48 | import javax.swing.JPanel; | |
49 | import javax.swing.JPopupMenu; | |
50 | import javax.swing.JRadioButtonMenuItem; | |
51 | import javax.swing.JScrollPane; | |
52 | ||
53 | import jalview.analysis.AAFrequency; | |
54 | import jalview.analysis.AlignmentAnnotationUtils; | |
55 | import jalview.analysis.AlignmentUtils; | |
56 | import jalview.analysis.Conservation; | |
57 | import jalview.api.AlignCalcWorkerI; | |
58 | import jalview.api.AlignViewportI; | |
59 | import jalview.bin.Console; | |
60 | import jalview.commands.ChangeCaseCommand; | |
61 | import jalview.commands.EditCommand; | |
62 | import jalview.commands.EditCommand.Action; | |
63 | import jalview.datamodel.AlignmentAnnotation; | |
64 | import jalview.datamodel.AlignmentI; | |
65 | import jalview.datamodel.DBRefEntry; | |
66 | import jalview.datamodel.HiddenColumns; | |
67 | import jalview.datamodel.MappedFeatures; | |
68 | import jalview.datamodel.PDBEntry; | |
69 | import jalview.datamodel.SequenceFeature; | |
70 | import jalview.datamodel.SequenceGroup; | |
71 | import jalview.datamodel.SequenceI; | |
72 | import jalview.gui.ColourMenuHelper.ColourChangeListener; | |
73 | import jalview.gui.JalviewColourChooser.ColourChooserListener; | |
74 | import jalview.io.FileFormatI; | |
75 | import jalview.io.FileFormats; | |
76 | import jalview.io.FormatAdapter; | |
77 | import jalview.io.SequenceAnnotationReport; | |
78 | import jalview.schemes.Blosum62ColourScheme; | |
79 | import jalview.schemes.ColourSchemeI; | |
80 | import jalview.schemes.ColourSchemes; | |
81 | import jalview.schemes.PIDColourScheme; | |
82 | import jalview.schemes.ResidueColourScheme; | |
83 | import jalview.util.Comparison; | |
84 | import jalview.util.GroupUrlLink; | |
85 | import jalview.util.GroupUrlLink.UrlStringTooLongException; | |
86 | import jalview.util.MessageManager; | |
87 | import jalview.util.Platform; | |
88 | import jalview.util.StringUtils; | |
89 | import jalview.util.UrlLink; | |
90 | import jalview.viewmodel.seqfeatures.FeatureRendererModel; | |
91 | import jalview.workers.SecondaryStructureConsensusThread; | |
92 | ||
93 | /** | |
94 | * The popup menu that is displayed on right-click on a sequence id, or in the | |
95 | * sequence alignment. | |
96 | */ | |
97 | public class PopupMenu extends JPopupMenu implements ColourChangeListener | |
98 | { | |
99 | /* | |
100 | * maximum length of feature description to include in popup menu item text | |
101 | */ | |
102 | private static final int FEATURE_DESC_MAX = 40; | |
103 | ||
104 | /* | |
105 | * true for ID Panel menu, false for alignment panel menu | |
106 | */ | |
107 | private final boolean forIdPanel; | |
108 | ||
109 | private final AlignmentPanel ap; | |
110 | ||
111 | /* | |
112 | * the sequence under the cursor when clicked | |
113 | * (additional sequences may be selected) | |
114 | */ | |
115 | private final SequenceI sequence; | |
116 | ||
117 | JMenu groupMenu = new JMenu(); | |
118 | ||
119 | JMenuItem groupName = new JMenuItem(); | |
120 | ||
121 | protected JCheckBoxMenuItem abovePIDColour = new JCheckBoxMenuItem(); | |
122 | ||
123 | protected JMenuItem modifyPID = new JMenuItem(); | |
124 | ||
125 | protected JCheckBoxMenuItem conservationMenuItem = new JCheckBoxMenuItem(); | |
126 | ||
127 | protected JRadioButtonMenuItem annotationColour; | |
128 | ||
129 | protected JMenuItem modifyConservation = new JMenuItem(); | |
130 | ||
131 | protected JCheckBoxMenuItem byConsensusSecondaryStructureMenuItem = new JCheckBoxMenuItem(); | |
132 | ||
133 | protected JMenuItem modifyConsensusSecondaryStructureThreshold = new JMenuItem(); | |
134 | ||
135 | JMenu sequenceMenu = new JMenu(); | |
136 | ||
137 | JMenuItem makeReferenceSeq = new JMenuItem(); | |
138 | ||
139 | JMenuItem createGroupMenuItem = new JMenuItem(); | |
140 | ||
141 | JMenuItem unGroupMenuItem = new JMenuItem(); | |
142 | ||
143 | JMenu colourMenu = new JMenu(); | |
144 | ||
145 | JCheckBoxMenuItem showBoxes = new JCheckBoxMenuItem(); | |
146 | ||
147 | JCheckBoxMenuItem showText = new JCheckBoxMenuItem(); | |
148 | ||
149 | JCheckBoxMenuItem showColourText = new JCheckBoxMenuItem(); | |
150 | ||
151 | JCheckBoxMenuItem displayNonconserved = new JCheckBoxMenuItem(); | |
152 | ||
153 | JMenu editMenu = new JMenu(); | |
154 | ||
155 | JMenuItem upperCase = new JMenuItem(); | |
156 | ||
157 | JMenuItem lowerCase = new JMenuItem(); | |
158 | ||
159 | JMenuItem toggle = new JMenuItem(); | |
160 | ||
161 | JMenu outputMenu = new JMenu(); | |
162 | ||
163 | JMenu seqShowAnnotationsMenu = new JMenu(); | |
164 | ||
165 | JMenu seqHideAnnotationsMenu = new JMenu(); | |
166 | ||
167 | JMenuItem seqAddReferenceAnnotations = new JMenuItem( | |
168 | MessageManager.getString("label.add_reference_annotations")); | |
169 | ||
170 | JMenu groupShowAnnotationsMenu = new JMenu(); | |
171 | ||
172 | JMenu groupHideAnnotationsMenu = new JMenu(); | |
173 | ||
174 | JMenuItem groupAddReferenceAnnotations = new JMenuItem( | |
175 | MessageManager.getString("label.add_reference_annotations")); | |
176 | ||
177 | JMenuItem textColour = new JMenuItem(); | |
178 | ||
179 | JMenu editGroupMenu = new JMenu(); | |
180 | ||
181 | JMenu groupShowAutoCalculatedAnnotations = new JMenu(); | |
182 | ||
183 | JMenu groupHideAutoCalculatedAnnotations = new JMenu(); | |
184 | ||
185 | JMenuItem chooseStructure = new JMenuItem(); | |
186 | ||
187 | JMenu rnaStructureMenu = new JMenu(); | |
188 | ||
189 | /** | |
190 | * Constructs a menu with sub-menu items for any hyperlinks for the sequence | |
191 | * and/or features provided. Hyperlinks may include a lookup by sequence id, | |
192 | * or database cross-references, depending on which links are enabled in user | |
193 | * preferences. | |
194 | * | |
195 | * @param seq | |
196 | * @param features | |
197 | * @return | |
198 | */ | |
199 | 26 | protected static JMenu buildLinkMenu(final SequenceI seq, |
200 | List<SequenceFeature> features) | |
201 | { | |
202 | 26 | JMenu linkMenu = new JMenu(MessageManager.getString("action.link")); |
203 | ||
204 | 26 | List<String> nlinks = null; |
205 | 26 | if (seq != null) |
206 | { | |
207 | 23 | nlinks = Preferences.sequenceUrlLinks.getLinksForMenu(); |
208 | 23 | UrlLink.sort(nlinks); |
209 | } | |
210 | else | |
211 | { | |
212 | 3 | nlinks = new ArrayList<>(); |
213 | } | |
214 | ||
215 | 26 | if (features != null) |
216 | { | |
217 | 26 | for (SequenceFeature sf : features) |
218 | { | |
219 | 2 | if (sf.links != null) |
220 | { | |
221 | 1 | for (String link : sf.links) |
222 | { | |
223 | 1 | nlinks.add(link); |
224 | } | |
225 | } | |
226 | } | |
227 | } | |
228 | ||
229 | /* | |
230 | * instantiate the hyperlinklink templates from sequence data; | |
231 | * note the order of the templates is preserved in the map | |
232 | */ | |
233 | 26 | Map<String, List<String>> linkset = new LinkedHashMap<>(); |
234 | 26 | for (String link : nlinks) |
235 | { | |
236 | 91 | UrlLink urlLink = null; |
237 | 91 | try |
238 | { | |
239 | 91 | urlLink = new UrlLink(link); |
240 | } catch (Exception foo) | |
241 | { | |
242 | 0 | Console.error("Exception for URLLink '" + link + "'", foo); |
243 | 0 | continue; |
244 | } | |
245 | ||
246 | 91 | if (!urlLink.isValid()) |
247 | { | |
248 | 0 | Console.error(urlLink.getInvalidMessage()); |
249 | 0 | continue; |
250 | } | |
251 | ||
252 | 91 | urlLink.createLinksFromSeq(seq, linkset); |
253 | } | |
254 | ||
255 | /* | |
256 | * construct menu items for the hyperlinks (still preserving | |
257 | * the order of the sorted templates) | |
258 | */ | |
259 | 26 | addUrlLinks(linkMenu, linkset.values()); |
260 | ||
261 | 26 | return linkMenu; |
262 | } | |
263 | ||
264 | /** | |
265 | * A helper method that builds menu items from the given links, with action | |
266 | * handlers to open the link URL, and adds them to the linkMenu. Each provided | |
267 | * link should be a list whose second item is the menu text, and whose fourth | |
268 | * item is the URL to open when the menu item is selected. | |
269 | * | |
270 | * @param linkMenu | |
271 | * @param linkset | |
272 | */ | |
273 | 26 | static private void addUrlLinks(JMenu linkMenu, |
274 | Collection<List<String>> linkset) | |
275 | { | |
276 | 26 | for (List<String> linkstrset : linkset) |
277 | { | |
278 | 30 | final String url = linkstrset.get(3); |
279 | 30 | JMenuItem item = new JMenuItem(linkstrset.get(1)); |
280 | 30 | item.setToolTipText(MessageManager |
281 | .formatMessage("label.open_url_param", new Object[] | |
282 | { url })); | |
283 | 30 | item.addActionListener(new ActionListener() |
284 | { | |
285 | 0 | @Override |
286 | public void actionPerformed(ActionEvent e) | |
287 | { | |
288 | 0 | new Thread(new Runnable() |
289 | { | |
290 | 0 | @Override |
291 | public void run() | |
292 | { | |
293 | 0 | showLink(url); |
294 | } | |
295 | }).start(); | |
296 | } | |
297 | }); | |
298 | 30 | linkMenu.add(item); |
299 | } | |
300 | } | |
301 | ||
302 | /** | |
303 | * Opens the provided url in the default web browser, or shows an error | |
304 | * message if this fails | |
305 | * | |
306 | * @param url | |
307 | */ | |
308 | 0 | static void showLink(String url) |
309 | { | |
310 | 0 | try |
311 | { | |
312 | 0 | jalview.util.BrowserLauncher.openURL(url); |
313 | } catch (Exception ex) | |
314 | { | |
315 | 0 | JvOptionPane.showInternalMessageDialog(Desktop.desktop, |
316 | MessageManager.getString("label.web_browser_not_found_unix"), | |
317 | MessageManager.getString("label.web_browser_not_found"), | |
318 | JvOptionPane.WARNING_MESSAGE); | |
319 | ||
320 | 0 | ex.printStackTrace(); |
321 | } | |
322 | } | |
323 | ||
324 | /** | |
325 | * add a late bound groupURL item to the given linkMenu | |
326 | * | |
327 | * @param linkMenu | |
328 | * @param label | |
329 | * - menu label string | |
330 | * @param urlgenerator | |
331 | * GroupURLLink used to generate URL | |
332 | * @param urlstub | |
333 | * Object array returned from the makeUrlStubs function. | |
334 | */ | |
335 | 0 | static void addshowLink(JMenu linkMenu, String label, |
336 | final GroupUrlLink urlgenerator, final Object[] urlstub) | |
337 | { | |
338 | 0 | JMenuItem item = new JMenuItem(label); |
339 | 0 | item.setToolTipText(MessageManager |
340 | .formatMessage("label.open_url_seqs_param", new Object[] | |
341 | { urlgenerator.getUrl_prefix(), | |
342 | urlgenerator.getNumberInvolved(urlstub) })); | |
343 | // TODO: put in info about what is being sent. | |
344 | 0 | item.addActionListener(new ActionListener() |
345 | { | |
346 | 0 | @Override |
347 | public void actionPerformed(ActionEvent e) | |
348 | { | |
349 | 0 | new Thread(new Runnable() |
350 | { | |
351 | ||
352 | 0 | @Override |
353 | public void run() | |
354 | { | |
355 | 0 | try |
356 | { | |
357 | 0 | showLink(urlgenerator.constructFrom(urlstub)); |
358 | } catch (UrlStringTooLongException e2) | |
359 | { | |
360 | } | |
361 | } | |
362 | ||
363 | }).start(); | |
364 | } | |
365 | }); | |
366 | ||
367 | 0 | linkMenu.add(item); |
368 | } | |
369 | ||
370 | /** | |
371 | * Constructor for a PopupMenu for a click in the alignment panel (on a | |
372 | * residue) | |
373 | * | |
374 | * @param ap | |
375 | * the panel in which the mouse is clicked | |
376 | * @param seq | |
377 | * the sequence under the mouse | |
378 | * @throws NullPointerException | |
379 | * if seq is null | |
380 | */ | |
381 | 0 | public PopupMenu(final AlignmentPanel ap, SequenceI seq, int column) |
382 | { | |
383 | 0 | this(false, ap, seq, column, null); |
384 | } | |
385 | ||
386 | /** | |
387 | * Constructor for a PopupMenu for a click in the sequence id panel | |
388 | * | |
389 | * @param alignPanel | |
390 | * the panel in which the mouse is clicked | |
391 | * @param seq | |
392 | * the sequence under the mouse click | |
393 | * @param groupLinks | |
394 | * templates for sequence external links | |
395 | * @throws NullPointerException | |
396 | * if seq is null | |
397 | */ | |
398 | 20 | public PopupMenu(final AlignmentPanel alignPanel, final SequenceI seq, |
399 | List<String> groupLinks) | |
400 | { | |
401 | 20 | this(true, alignPanel, seq, -1, groupLinks); |
402 | } | |
403 | ||
404 | /** | |
405 | * Private constructor that constructs a popup menu for either sequence ID | |
406 | * Panel, or alignment context | |
407 | * | |
408 | * @param fromIdPanel | |
409 | * @param alignPanel | |
410 | * @param seq | |
411 | * @param column | |
412 | * aligned column position (0...) | |
413 | * @param groupLinks | |
414 | */ | |
415 | 20 | private PopupMenu(boolean fromIdPanel, final AlignmentPanel alignPanel, |
416 | final SequenceI seq, final int column, List<String> groupLinks) | |
417 | { | |
418 | 20 | Objects.requireNonNull(seq); |
419 | 20 | this.forIdPanel = fromIdPanel; |
420 | 20 | this.ap = alignPanel; |
421 | 20 | sequence = seq; |
422 | ||
423 | 20 | for (String ff : FileFormats.getInstance().getWritableFormats(true)) |
424 | { | |
425 | 220 | JMenuItem item = new JMenuItem(ff); |
426 | ||
427 | 220 | item.addActionListener(new ActionListener() |
428 | { | |
429 | 0 | @Override |
430 | public void actionPerformed(ActionEvent e) | |
431 | { | |
432 | 0 | outputText_actionPerformed(e); |
433 | } | |
434 | }); | |
435 | ||
436 | 220 | outputMenu.add(item); |
437 | } | |
438 | ||
439 | /* | |
440 | * Build menus for annotation types that may be shown or hidden, and for | |
441 | * 'reference annotations' that may be added to the alignment. First for the | |
442 | * currently selected sequence (if there is one): | |
443 | */ | |
444 | 20 | final List<SequenceI> selectedSequence = (forIdPanel && seq != null |
445 | ? Arrays.asList(seq) | |
446 | : Collections.<SequenceI> emptyList()); | |
447 | 20 | buildAnnotationTypesMenus(seqShowAnnotationsMenu, |
448 | seqHideAnnotationsMenu, selectedSequence); | |
449 | 20 | configureReferenceAnnotationsMenu(seqAddReferenceAnnotations, |
450 | selectedSequence); | |
451 | ||
452 | /* | |
453 | * And repeat for the current selection group (if there is one): | |
454 | */ | |
455 | 20 | final List<SequenceI> selectedGroup = (alignPanel.av |
456 | .getSelectionGroup() == null | |
457 | ? Collections.<SequenceI> emptyList() | |
458 | : alignPanel.av.getSelectionGroup().getSequences()); | |
459 | 20 | buildAnnotationTypesMenus(groupShowAnnotationsMenu, |
460 | groupHideAnnotationsMenu, selectedGroup); | |
461 | 20 | configureReferenceAnnotationsMenu(groupAddReferenceAnnotations, |
462 | selectedGroup); | |
463 | ||
464 | // If a sequence group is selected, build show/hide auto calculated | |
465 | // annotations menu | |
466 | 20 | SequenceGroup selectedSequenceGroup = alignPanel.av.getSelectionGroup(); |
467 | 20 | if (selectedSequenceGroup != null) |
468 | { | |
469 | 4 | buildAutoCalculatedAnnotationsMenu(groupShowAutoCalculatedAnnotations, |
470 | groupHideAutoCalculatedAnnotations, selectedSequenceGroup); | |
471 | } | |
472 | ||
473 | 20 | try |
474 | { | |
475 | 20 | jbInit(); |
476 | } catch (Exception e) | |
477 | { | |
478 | 0 | e.printStackTrace(); |
479 | } | |
480 | ||
481 | 20 | if (forIdPanel) |
482 | { | |
483 | 20 | JMenuItem menuItem; |
484 | 20 | sequenceMenu.setText(sequence.getName()); |
485 | 20 | if (seq == alignPanel.av.getAlignment().getSeqrep()) |
486 | { | |
487 | 0 | makeReferenceSeq.setText( |
488 | MessageManager.getString("action.unmark_as_reference")); | |
489 | } | |
490 | else | |
491 | { | |
492 | 20 | makeReferenceSeq.setText( |
493 | MessageManager.getString("action.set_as_reference")); | |
494 | } | |
495 | ||
496 | 20 | if (!alignPanel.av.getAlignment().isNucleotide()) |
497 | { | |
498 | 19 | remove(rnaStructureMenu); |
499 | } | |
500 | else | |
501 | { | |
502 | 1 | int origCount = rnaStructureMenu.getItemCount(); |
503 | /* | |
504 | * add menu items to 2D-render any alignment or sequence secondary | |
505 | * structure annotation | |
506 | */ | |
507 | 1 | AlignmentAnnotation[] aas = alignPanel.av.getAlignment() |
508 | .getAlignmentAnnotation(); | |
509 | 1 | if (aas != null) |
510 | { | |
511 | 1 | for (final AlignmentAnnotation aa : aas) |
512 | { | |
513 | 2 | if (aa.isValidStruc() && aa.sequenceRef == null) |
514 | { | |
515 | /* | |
516 | * valid alignment RNA secondary structure annotation | |
517 | */ | |
518 | 0 | menuItem = new JMenuItem(); |
519 | 0 | menuItem.setText(MessageManager.formatMessage( |
520 | "label.2d_rna_structure_line", new Object[] | |
521 | { aa.label })); | |
522 | 0 | menuItem.addActionListener(new ActionListener() |
523 | { | |
524 | 0 | @Override |
525 | public void actionPerformed(ActionEvent e) | |
526 | { | |
527 | 0 | new AppVarna(seq, aa, alignPanel); |
528 | } | |
529 | }); | |
530 | 0 | rnaStructureMenu.add(menuItem); |
531 | } | |
532 | } | |
533 | } | |
534 | ||
535 | 1 | if (seq.getAnnotation() != null) |
536 | { | |
537 | 0 | AlignmentAnnotation seqAnns[] = seq.getAnnotation(); |
538 | 0 | for (final AlignmentAnnotation aa : seqAnns) |
539 | { | |
540 | 0 | if (aa.isValidStruc()) |
541 | { | |
542 | /* | |
543 | * valid sequence RNA secondary structure annotation | |
544 | */ | |
545 | // TODO: make rnastrucF a bit more nice | |
546 | 0 | menuItem = new JMenuItem(); |
547 | 0 | menuItem.setText(MessageManager.formatMessage( |
548 | "label.2d_rna_sequence_name", new Object[] | |
549 | { seq.getName() })); | |
550 | 0 | menuItem.addActionListener(new ActionListener() |
551 | { | |
552 | 0 | @Override |
553 | public void actionPerformed(ActionEvent e) | |
554 | { | |
555 | // TODO: VARNA does'nt print gaps in the sequence | |
556 | 0 | new AppVarna(seq, aa, alignPanel); |
557 | } | |
558 | }); | |
559 | 0 | rnaStructureMenu.add(menuItem); |
560 | } | |
561 | } | |
562 | } | |
563 | 1 | if (rnaStructureMenu.getItemCount() == origCount) |
564 | { | |
565 | 1 | remove(rnaStructureMenu); |
566 | } | |
567 | } | |
568 | ||
569 | 20 | menuItem = new JMenuItem( |
570 | MessageManager.getString("action.hide_sequences")); | |
571 | 20 | menuItem.addActionListener(new ActionListener() |
572 | { | |
573 | 0 | @Override |
574 | public void actionPerformed(ActionEvent e) | |
575 | { | |
576 | 0 | hideSequences(false); |
577 | } | |
578 | }); | |
579 | 20 | add(menuItem); |
580 | ||
581 | 20 | if (alignPanel.av.getSelectionGroup() != null |
582 | && alignPanel.av.getSelectionGroup().getSize() > 1) | |
583 | { | |
584 | 1 | menuItem = new JMenuItem(MessageManager |
585 | .formatMessage("label.represent_group_with", new Object[] | |
586 | { seq.getName() })); | |
587 | 1 | menuItem.addActionListener(new ActionListener() |
588 | { | |
589 | 0 | @Override |
590 | public void actionPerformed(ActionEvent e) | |
591 | { | |
592 | 0 | hideSequences(true); |
593 | } | |
594 | }); | |
595 | 1 | sequenceMenu.add(menuItem); |
596 | } | |
597 | ||
598 | 20 | if (alignPanel.av.hasHiddenRows()) |
599 | { | |
600 | 0 | final int index = alignPanel.av.getAlignment().findIndex(seq); |
601 | ||
602 | 0 | if (alignPanel.av.adjustForHiddenSeqs(index) |
603 | - alignPanel.av.adjustForHiddenSeqs(index - 1) > 1) | |
604 | { | |
605 | 0 | menuItem = new JMenuItem( |
606 | MessageManager.getString("action.reveal_sequences")); | |
607 | 0 | menuItem.addActionListener(new ActionListener() |
608 | { | |
609 | 0 | @Override |
610 | public void actionPerformed(ActionEvent e) | |
611 | { | |
612 | 0 | alignPanel.av.showSequence(index); |
613 | 0 | if (alignPanel.overviewPanel != null) |
614 | { | |
615 | 0 | alignPanel.overviewPanel.updateOverviewImage(); |
616 | } | |
617 | } | |
618 | }); | |
619 | 0 | add(menuItem); |
620 | } | |
621 | } | |
622 | } | |
623 | ||
624 | /* | |
625 | * offer 'Reveal All' | |
626 | * - in the IdPanel (seq not null) if any sequence is hidden | |
627 | * - in the IdPanel or SeqPanel if all sequences are hidden (seq is null) | |
628 | */ | |
629 | 20 | if (alignPanel.av.hasHiddenRows()) |
630 | { | |
631 | 0 | boolean addOption = seq != null; |
632 | 0 | if (!addOption && alignPanel.av.getAlignment().getHeight() == 0) |
633 | { | |
634 | 0 | addOption = true; |
635 | } | |
636 | 0 | if (addOption) |
637 | { | |
638 | 0 | JMenuItem menuItem = new JMenuItem( |
639 | MessageManager.getString("action.reveal_all")); | |
640 | 0 | menuItem.addActionListener(new ActionListener() |
641 | { | |
642 | 0 | @Override |
643 | public void actionPerformed(ActionEvent e) | |
644 | { | |
645 | 0 | alignPanel.av.showAllHiddenSeqs(); |
646 | 0 | if (alignPanel.overviewPanel != null) |
647 | { | |
648 | 0 | alignPanel.overviewPanel.updateOverviewImage(); |
649 | } | |
650 | } | |
651 | }); | |
652 | 0 | add(menuItem); |
653 | } | |
654 | } | |
655 | ||
656 | 20 | SequenceGroup sg = alignPanel.av.getSelectionGroup(); |
657 | 20 | boolean isDefinedGroup = (sg != null) |
658 | ? alignPanel.av.getAlignment().getGroups().contains(sg) | |
659 | : false; | |
660 | ||
661 | 20 | if (sg != null && sg.getSize() > 0) |
662 | { | |
663 | 4 | groupName.setText(MessageManager |
664 | .getString("label.edit_name_and_description_current_group")); | |
665 | ||
666 | 4 | ColourMenuHelper.setColourSelected(colourMenu, sg.getColourScheme()); |
667 | ||
668 | 4 | conservationMenuItem.setEnabled(!sg.isNucleotide()); |
669 | ||
670 | 4 | byConsensusSecondaryStructureMenuItem.setEnabled(!sg.isNucleotide()); |
671 | ||
672 | 4 | if (sg.cs != null) |
673 | { | |
674 | 4 | if (sg.cs.conservationApplied()) |
675 | { | |
676 | 0 | conservationMenuItem.setSelected(true); |
677 | } | |
678 | 4 | if (sg.cs.getThreshold() > 0) |
679 | { | |
680 | 0 | abovePIDColour.setSelected(true); |
681 | } | |
682 | 4 | if (sg.cs.isConsensusSecondaryStructureColouring()) |
683 | { | |
684 | 0 | byConsensusSecondaryStructureMenuItem.setSelected(true); |
685 | } | |
686 | } | |
687 | 4 | modifyConservation.setEnabled(conservationMenuItem.isSelected()); |
688 | 4 | modifyPID.setEnabled(abovePIDColour.isSelected()); |
689 | 4 | modifyConsensusSecondaryStructureThreshold.setEnabled( |
690 | byConsensusSecondaryStructureMenuItem.isSelected()); | |
691 | 4 | displayNonconserved.setSelected(sg.getShowNonconserved()); |
692 | 4 | showText.setSelected(sg.getDisplayText()); |
693 | 4 | showColourText.setSelected(sg.getColourText()); |
694 | 4 | showBoxes.setSelected(sg.getDisplayBoxes()); |
695 | // add any groupURLs to the groupURL submenu and make it visible | |
696 | 4 | if (groupLinks != null && groupLinks.size() > 0) |
697 | { | |
698 | 0 | buildGroupURLMenu(sg, groupLinks); |
699 | } | |
700 | // Add a 'show all structures' for the current selection | |
701 | 4 | Hashtable<String, PDBEntry> pdbe = new Hashtable<>(), |
702 | reppdb = new Hashtable<>(); | |
703 | ||
704 | 4 | SequenceI sqass = null; |
705 | 4 | for (SequenceI sq : alignPanel.av.getSequenceSelection()) |
706 | { | |
707 | 5 | Vector<PDBEntry> pes = sq.getDatasetSequence().getAllPDBEntries(); |
708 | 5 | if (pes != null && pes.size() > 0) |
709 | { | |
710 | 0 | reppdb.put(pes.get(0).getId(), pes.get(0)); |
711 | 0 | for (PDBEntry pe : pes) |
712 | { | |
713 | 0 | pdbe.put(pe.getId(), pe); |
714 | 0 | if (sqass == null) |
715 | { | |
716 | 0 | sqass = sq; |
717 | } | |
718 | } | |
719 | } | |
720 | } | |
721 | 4 | if (pdbe.size() > 0) |
722 | { | |
723 | 0 | final PDBEntry[] pe = pdbe.values() |
724 | .toArray(new PDBEntry[pdbe.size()]), | |
725 | pr = reppdb.values().toArray(new PDBEntry[reppdb.size()]); | |
726 | 0 | final JMenuItem gpdbview, rpdbview; |
727 | } | |
728 | } | |
729 | else | |
730 | { | |
731 | 16 | groupMenu.setVisible(false); |
732 | 16 | editMenu.setVisible(false); |
733 | } | |
734 | ||
735 | 20 | if (!isDefinedGroup) |
736 | { | |
737 | 20 | createGroupMenuItem.setVisible(true); |
738 | 20 | unGroupMenuItem.setVisible(false); |
739 | 20 | editGroupMenu |
740 | .setText(MessageManager.getString("action.edit_new_group")); | |
741 | ||
742 | // Hide show/hide auto calculated annotations menus for group if a | |
743 | // sequence | |
744 | // group is not defined. | |
745 | 20 | groupShowAutoCalculatedAnnotations.setVisible(false); |
746 | 20 | groupHideAutoCalculatedAnnotations.setVisible(false); |
747 | } | |
748 | else | |
749 | { | |
750 | 0 | createGroupMenuItem.setVisible(false); |
751 | 0 | unGroupMenuItem.setVisible(true); |
752 | 0 | editGroupMenu.setText(MessageManager.getString("action.edit_group")); |
753 | ||
754 | // Show show/hide auto calculated annotations menus for group if a | |
755 | // sequence | |
756 | // group is defined and showGroupSSConsensus is true. Hide the menus | |
757 | // otherwise. | |
758 | 0 | if (alignPanel.av.isShowGroupSSConsensus()) |
759 | { | |
760 | 0 | groupShowAutoCalculatedAnnotations.setVisible(true); |
761 | 0 | groupHideAutoCalculatedAnnotations.setVisible(true); |
762 | } | |
763 | else | |
764 | { | |
765 | 0 | groupShowAutoCalculatedAnnotations.setVisible(false); |
766 | 0 | groupHideAutoCalculatedAnnotations.setVisible(false); |
767 | } | |
768 | } | |
769 | ||
770 | 20 | if (!forIdPanel) |
771 | { | |
772 | 0 | sequenceMenu.setVisible(false); |
773 | 0 | chooseStructure.setVisible(false); |
774 | 0 | rnaStructureMenu.setVisible(false); |
775 | } | |
776 | ||
777 | 20 | addLinksAndFeatures(seq, column); |
778 | } | |
779 | ||
780 | /** | |
781 | * Adds | |
782 | * <ul> | |
783 | * <li>configured sequence database links (ID panel popup menu)</li> | |
784 | * <li>non-positional feature links (ID panel popup menu)</li> | |
785 | * <li>positional feature links (alignment panel popup menu)</li> | |
786 | * <li>feature details links (alignment panel popup menu)</li> | |
787 | * </ul> | |
788 | * If this panel is also showed complementary (CDS/protein) features, then | |
789 | * links to their feature details are also added. | |
790 | * | |
791 | * @param seq | |
792 | * @param column | |
793 | */ | |
794 | 20 | void addLinksAndFeatures(final SequenceI seq, final int column) |
795 | { | |
796 | 20 | List<SequenceFeature> features = null; |
797 | 20 | if (forIdPanel) |
798 | { | |
799 | 20 | features = sequence.getFeatures().getNonPositionalFeatures(); |
800 | } | |
801 | else | |
802 | { | |
803 | 0 | features = ap.getFeatureRenderer().findFeaturesAtColumn(sequence, |
804 | column + 1); | |
805 | } | |
806 | ||
807 | 20 | addLinks(seq, features); |
808 | ||
809 | 20 | if (!forIdPanel) |
810 | { | |
811 | 0 | addFeatureDetails(features, seq, column); |
812 | } | |
813 | } | |
814 | ||
815 | /** | |
816 | * Add a menu item to show feature details for each sequence feature. Any | |
817 | * linked 'virtual' features (CDS/protein) are also optionally found and | |
818 | * included. | |
819 | * | |
820 | * @param features | |
821 | * @param seq | |
822 | * @param column | |
823 | */ | |
824 | 3 | protected void addFeatureDetails(List<SequenceFeature> features, |
825 | final SequenceI seq, final int column) | |
826 | { | |
827 | /* | |
828 | * add features in CDS/protein complement at the corresponding | |
829 | * position if configured to do so | |
830 | */ | |
831 | 3 | MappedFeatures mf = null; |
832 | 3 | if (ap.av.isShowComplementFeatures()) |
833 | { | |
834 | 0 | if (!Comparison.isGap(sequence.getCharAt(column))) |
835 | { | |
836 | 0 | AlignViewportI complement = ap.getAlignViewport() |
837 | .getCodingComplement(); | |
838 | 0 | AlignFrame af = Desktop.getAlignFrameFor(complement); |
839 | 0 | FeatureRendererModel fr2 = af.getFeatureRenderer(); |
840 | 0 | int seqPos = sequence.findPosition(column); |
841 | 0 | mf = fr2.findComplementFeaturesAtResidue(sequence, seqPos); |
842 | } | |
843 | } | |
844 | ||
845 | 3 | if (features.isEmpty() && mf == null) |
846 | { | |
847 | /* | |
848 | * no features to show at this position | |
849 | */ | |
850 | 1 | return; |
851 | } | |
852 | ||
853 | 2 | JMenu details = new JMenu( |
854 | MessageManager.getString("label.feature_details")); | |
855 | 2 | add(details); |
856 | ||
857 | 2 | String name = seq.getName(); |
858 | 2 | for (final SequenceFeature sf : features) |
859 | { | |
860 | 4 | addFeatureDetailsMenuItem(details, name, sf, null); |
861 | } | |
862 | ||
863 | 2 | if (mf != null) |
864 | { | |
865 | 0 | for (final SequenceFeature sf : mf.features) |
866 | { | |
867 | 0 | addFeatureDetailsMenuItem(details, name, sf, mf); |
868 | } | |
869 | } | |
870 | } | |
871 | ||
872 | /** | |
873 | * A helper method to add one menu item whose action is to show details for | |
874 | * one feature. The menu text includes feature description, but this may be | |
875 | * truncated. | |
876 | * | |
877 | * @param details | |
878 | * @param seqName | |
879 | * @param sf | |
880 | * @param mf | |
881 | */ | |
882 | 4 | void addFeatureDetailsMenuItem(JMenu details, final String seqName, |
883 | final SequenceFeature sf, MappedFeatures mf) | |
884 | { | |
885 | 4 | int start = sf.getBegin(); |
886 | 4 | int end = sf.getEnd(); |
887 | 4 | if (mf != null) |
888 | { | |
889 | /* | |
890 | * show local rather than linked feature coordinates | |
891 | */ | |
892 | 0 | int[] localRange = mf.getMappedPositions(start, end); |
893 | 0 | if (localRange == null) |
894 | { | |
895 | // e.g. variant extending to stop codon so not mappable | |
896 | 0 | return; |
897 | } | |
898 | 0 | start = localRange[0]; |
899 | 0 | end = localRange[localRange.length - 1]; |
900 | } | |
901 | 4 | StringBuilder desc = new StringBuilder(); |
902 | 4 | desc.append(sf.getType()).append(" ").append(String.valueOf(start)); |
903 | 4 | if (start != end) |
904 | { | |
905 | 2 | desc.append(sf.isContactFeature() ? ":" : "-"); |
906 | 2 | desc.append(String.valueOf(end)); |
907 | } | |
908 | 4 | String description = sf.getDescription(); |
909 | 4 | if (description != null) |
910 | { | |
911 | 4 | desc.append(" "); |
912 | 4 | description = StringUtils.stripHtmlTags(description); |
913 | ||
914 | /* | |
915 | * truncate overlong descriptions unless they contain an href | |
916 | * (as truncation could leave corrupted html) | |
917 | */ | |
918 | 4 | boolean hasLink = description.indexOf("a href") > -1; |
919 | 4 | if (description.length() > FEATURE_DESC_MAX && !hasLink) |
920 | { | |
921 | 1 | description = description.substring(0, FEATURE_DESC_MAX) + "..."; |
922 | } | |
923 | 4 | desc.append(description); |
924 | } | |
925 | 4 | String featureGroup = sf.getFeatureGroup(); |
926 | 4 | if (featureGroup != null) |
927 | { | |
928 | 2 | desc.append(" (").append(featureGroup).append(")"); |
929 | } | |
930 | 4 | String htmlText = JvSwingUtils.wrapTooltip(true, desc.toString()); |
931 | 4 | JMenuItem item = new JMenuItem(htmlText); |
932 | 4 | item.addActionListener(new ActionListener() |
933 | { | |
934 | 0 | @Override |
935 | public void actionPerformed(ActionEvent e) | |
936 | { | |
937 | 0 | showFeatureDetails(sf, seqName, mf); |
938 | } | |
939 | }); | |
940 | 4 | details.add(item); |
941 | } | |
942 | ||
943 | /** | |
944 | * Opens a panel showing a text report of feature details | |
945 | * | |
946 | * @param sf | |
947 | * @param seqName | |
948 | * @param mf | |
949 | */ | |
950 | 0 | protected void showFeatureDetails(SequenceFeature sf, String seqName, |
951 | MappedFeatures mf) | |
952 | { | |
953 | 0 | JInternalFrame details; |
954 | 0 | if (Platform.isJS()) |
955 | { | |
956 | 0 | details = new JInternalFrame(); |
957 | 0 | details.setFrameIcon(null); |
958 | 0 | JPanel panel = new JPanel(new BorderLayout()); |
959 | 0 | panel.setOpaque(true); |
960 | 0 | panel.setBackground(Color.white); |
961 | // TODO JAL-3026 set style of table correctly for feature details | |
962 | 0 | JLabel reprt = new JLabel(MessageManager |
963 | .formatMessage("label.html_content", new Object[] | |
964 | { sf.getDetailsReport(seqName, mf) })); | |
965 | 0 | reprt.setBackground(Color.WHITE); |
966 | 0 | reprt.setOpaque(true); |
967 | 0 | panel.add(reprt, BorderLayout.CENTER); |
968 | 0 | details.setContentPane(panel); |
969 | 0 | details.pack(); |
970 | } | |
971 | else | |
972 | /** | |
973 | * Java only | |
974 | * | |
975 | * @j2sIgnore | |
976 | */ | |
977 | { | |
978 | 0 | CutAndPasteHtmlTransfer cap = new CutAndPasteHtmlTransfer(); |
979 | // it appears Java's CSS does not support border-collapse :-( | |
980 | 0 | cap.addStylesheetRule("table { border-collapse: collapse;}"); |
981 | 0 | cap.addStylesheetRule("table, td, th {border: 1px solid black;}"); |
982 | 0 | cap.setText(sf.getDetailsReport(seqName, mf)); |
983 | 0 | details = cap; |
984 | } | |
985 | 0 | Desktop.addInternalFrame(details, |
986 | MessageManager.getString("label.feature_details"), 500, 500); | |
987 | } | |
988 | ||
989 | /** | |
990 | * Adds a 'Link' menu item with a sub-menu item for each hyperlink provided. | |
991 | * When seq is not null, these are links for the sequence id, which may be to | |
992 | * external web sites for the sequence accession, and/or links embedded in | |
993 | * non-positional features. When seq is null, only links embedded in the | |
994 | * provided features are added. If no links are found, the menu is not added. | |
995 | * | |
996 | * @param seq | |
997 | * @param features | |
998 | */ | |
999 | 20 | void addLinks(final SequenceI seq, List<SequenceFeature> features) |
1000 | { | |
1001 | 20 | JMenu linkMenu = buildLinkMenu(forIdPanel ? seq : null, features); |
1002 | ||
1003 | // only add link menu if it has entries | |
1004 | 20 | if (linkMenu.getItemCount() > 0) |
1005 | { | |
1006 | 20 | if (forIdPanel) |
1007 | { | |
1008 | 20 | sequenceMenu.add(linkMenu); |
1009 | } | |
1010 | else | |
1011 | { | |
1012 | 0 | add(linkMenu); |
1013 | } | |
1014 | } | |
1015 | } | |
1016 | ||
1017 | /** | |
1018 | * Add annotation types to 'Show annotations' and/or 'Hide annotations' menus. | |
1019 | * "All" is added first, followed by a separator. Then add any annotation | |
1020 | * types associated with the current selection. Separate menus are built for | |
1021 | * the selected sequence group (if any), and the selected sequence. | |
1022 | * <p> | |
1023 | * Some annotation rows are always rendered together - these can be identified | |
1024 | * by a common graphGroup property > -1. Only one of each group will be marked | |
1025 | * as visible (to avoid duplication of the display). For such groups we add a | |
1026 | * composite type name, e.g. | |
1027 | * <p> | |
1028 | * IUPredWS (Long), IUPredWS (Short) | |
1029 | * | |
1030 | * @param seq | |
1031 | */ | |
1032 | 43 | protected void buildAnnotationTypesMenus(JMenu showMenu, JMenu hideMenu, |
1033 | List<SequenceI> forSequences) | |
1034 | { | |
1035 | 43 | showMenu.removeAll(); |
1036 | 43 | hideMenu.removeAll(); |
1037 | ||
1038 | 43 | final List<String> all = Arrays |
1039 | .asList(new String[] | |
1040 | { MessageManager.getString("label.all") }); | |
1041 | 43 | addAnnotationTypeToShowHide(showMenu, forSequences, "", all, true, |
1042 | true); | |
1043 | 43 | addAnnotationTypeToShowHide(hideMenu, forSequences, "", all, true, |
1044 | false); | |
1045 | 43 | showMenu.addSeparator(); |
1046 | 43 | hideMenu.addSeparator(); |
1047 | ||
1048 | 43 | final AlignmentAnnotation[] annotations = ap.getAlignment() |
1049 | .getAlignmentAnnotation(); | |
1050 | ||
1051 | /* | |
1052 | * Find shown/hidden annotations types, distinguished by source (calcId), | |
1053 | * and grouped by graphGroup. Using LinkedHashMap means we will retrieve in | |
1054 | * the insertion order, which is the order of the annotations on the | |
1055 | * alignment. | |
1056 | */ | |
1057 | 43 | Map<String, List<List<String>>> shownTypes = new LinkedHashMap<>(); |
1058 | 43 | Map<String, List<List<String>>> hiddenTypes = new LinkedHashMap<>(); |
1059 | 43 | AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes, hiddenTypes, |
1060 | AlignmentAnnotationUtils.asList(annotations), forSequences); | |
1061 | ||
1062 | 43 | for (String calcId : hiddenTypes.keySet()) |
1063 | { | |
1064 | 4 | for (List<String> type : hiddenTypes.get(calcId)) |
1065 | { | |
1066 | 4 | addAnnotationTypeToShowHide(showMenu, forSequences, calcId, type, |
1067 | false, true); | |
1068 | } | |
1069 | } | |
1070 | // grey out 'show annotations' if none are hidden | |
1071 | 43 | showMenu.setEnabled(!hiddenTypes.isEmpty()); |
1072 | ||
1073 | 43 | for (String calcId : shownTypes.keySet()) |
1074 | { | |
1075 | 2 | for (List<String> type : shownTypes.get(calcId)) |
1076 | { | |
1077 | 4 | addAnnotationTypeToShowHide(hideMenu, forSequences, calcId, type, |
1078 | false, false); | |
1079 | } | |
1080 | } | |
1081 | // grey out 'hide annotations' if none are shown | |
1082 | 43 | hideMenu.setEnabled(!shownTypes.isEmpty()); |
1083 | } | |
1084 | ||
1085 | /** | |
1086 | * Builds the menu for showing and hiding auto calculated annotations for a | |
1087 | * selected sequence group. It clears existing menu items and adds menu items | |
1088 | * for showing/hiding annotations. The menu is populated based on the current | |
1089 | * visible status. | |
1090 | * | |
1091 | * @param groupShowAutoCalculatedAnnotations | |
1092 | * The menu for showing auto calculated annotations. | |
1093 | * @param groupHideAutoCalculatedAnnotations | |
1094 | * The menu for hiding auto calculated annotations. | |
1095 | * @param selectedSequenceGroup | |
1096 | * The sequence group selected by the user. | |
1097 | */ | |
1098 | 4 | protected void buildAutoCalculatedAnnotationsMenu( |
1099 | JMenu groupShowAutoCalculatedAnnotations, | |
1100 | JMenu groupHideAutoCalculatedAnnotations, | |
1101 | SequenceGroup selectedSequenceGroup) | |
1102 | { | |
1103 | ||
1104 | // Clear all existing items from the menus | |
1105 | 4 | groupShowAutoCalculatedAnnotations.removeAll(); |
1106 | 4 | groupHideAutoCalculatedAnnotations.removeAll(); |
1107 | ||
1108 | // Add "All" menu item to both show and hide menus. | |
1109 | 4 | final String all = MessageManager.getString("label.all"); |
1110 | 4 | addAutoCalculatedAnnotationTypeToShowHide( |
1111 | groupShowAutoCalculatedAnnotations, selectedSequenceGroup, all, | |
1112 | true, true); | |
1113 | 4 | addAutoCalculatedAnnotationTypeToShowHide( |
1114 | groupHideAutoCalculatedAnnotations, selectedSequenceGroup, all, | |
1115 | true, false); | |
1116 | ||
1117 | // Add separators after "All" | |
1118 | 4 | groupShowAutoCalculatedAnnotations.addSeparator(); |
1119 | 4 | groupHideAutoCalculatedAnnotations.addSeparator(); |
1120 | ||
1121 | // Get the alignment annotations | |
1122 | 4 | final AlignmentAnnotation[] annotations = ap.getAlignment() |
1123 | .getAlignmentAnnotation(); | |
1124 | ||
1125 | // Lists to hold shown and hidden annotation types | |
1126 | 4 | List<String> shownTypes = new ArrayList<>(); |
1127 | 4 | List<String> hiddenTypes = new ArrayList<>(); |
1128 | ||
1129 | // Populate the lists of shown and hidden annotation types based on the | |
1130 | // current visible status for the selected sequence group | |
1131 | 4 | AlignmentAnnotationUtils |
1132 | .getShownHiddenSecondaryStructureProvidersForGroup(shownTypes, | |
1133 | hiddenTypes, | |
1134 | AlignmentAnnotationUtils.asList(annotations), | |
1135 | selectedSequenceGroup); | |
1136 | ||
1137 | // Add code if additional auto calculated annotation types (like residue | |
1138 | // consensus, | |
1139 | // conservation, etc.) are needed for a selected group | |
1140 | ||
1141 | // Add currently hidden types to the show menu | |
1142 | 4 | for (String shownType : shownTypes) |
1143 | { | |
1144 | 0 | addAutoCalculatedAnnotationTypeToShowHide( |
1145 | groupHideAutoCalculatedAnnotations, selectedSequenceGroup, | |
1146 | shownType, false, false); | |
1147 | } | |
1148 | ||
1149 | // Add currently shown types to the hide menu | |
1150 | 4 | for (String hiddenType : hiddenTypes) |
1151 | { | |
1152 | 0 | addAutoCalculatedAnnotationTypeToShowHide( |
1153 | groupShowAutoCalculatedAnnotations, selectedSequenceGroup, | |
1154 | hiddenType, false, true); | |
1155 | } | |
1156 | ||
1157 | // Enable or disable the menus based on whether there are any hidden | |
1158 | // or shown types | |
1159 | 4 | groupShowAutoCalculatedAnnotations.setEnabled(!hiddenTypes.isEmpty()); |
1160 | 4 | groupHideAutoCalculatedAnnotations.setEnabled(!shownTypes.isEmpty()); |
1161 | } | |
1162 | ||
1163 | /** | |
1164 | * Adds a menu item to the provided menu for showing or hiding a specific type | |
1165 | * of auto calculated annotation | |
1166 | * | |
1167 | * @param showOrHideAutoCalculatedAnnotationsMenu | |
1168 | * The menu to which the item should be added. | |
1169 | * @param selectedSequenceGroup | |
1170 | * The selected sequence group for which the action will be | |
1171 | * performed. | |
1172 | * @param type | |
1173 | * The type of annotation to show or hide. | |
1174 | * @param allTypes | |
1175 | * Indicates if the action should apply to all annotation types. True | |
1176 | * if user selects "All". | |
1177 | * @param actionIsShow | |
1178 | * Indicates if the item is for showing (true) or hiding (false) the | |
1179 | * annotation type. | |
1180 | */ | |
1181 | 8 | protected void addAutoCalculatedAnnotationTypeToShowHide( |
1182 | JMenu showOrHideAutoCalculatedAnnotationsMenu, | |
1183 | final SequenceGroup selectedSequenceGroup, final String type, | |
1184 | final boolean allTypes, final boolean actionIsShow) | |
1185 | { | |
1186 | ||
1187 | // Create a new menu item with the type | |
1188 | 8 | final JMenuItem item = new JMenuItem(type); |
1189 | ||
1190 | // Add an action listener to the menu item | |
1191 | 8 | item.addActionListener(new ActionListener() |
1192 | { | |
1193 | 0 | @Override |
1194 | public void actionPerformed(ActionEvent e) | |
1195 | { | |
1196 | // Show or hide the auto calculated annotations for the selected group | |
1197 | 0 | AlignmentUtils.showOrHideAutoCalculatedAnnotationsForGroup( |
1198 | ap.getAlignment(), type, selectedSequenceGroup, allTypes, | |
1199 | actionIsShow); | |
1200 | ||
1201 | 0 | refresh(); |
1202 | } | |
1203 | }); | |
1204 | ||
1205 | // Add the menu item to the menu | |
1206 | 8 | showOrHideAutoCalculatedAnnotationsMenu.add(item); |
1207 | } | |
1208 | ||
1209 | /** | |
1210 | * Returns a list of sequences - either the current selection group (if there | |
1211 | * is one), else the specified single sequence. | |
1212 | * | |
1213 | * @param seq | |
1214 | * @return | |
1215 | */ | |
1216 | 0 | protected List<SequenceI> getSequenceScope(SequenceI seq) |
1217 | { | |
1218 | 0 | List<SequenceI> forSequences = null; |
1219 | 0 | final SequenceGroup selectionGroup = ap.av.getSelectionGroup(); |
1220 | 0 | if (selectionGroup != null && selectionGroup.getSize() > 0) |
1221 | { | |
1222 | 0 | forSequences = selectionGroup.getSequences(); |
1223 | } | |
1224 | else | |
1225 | { | |
1226 | 0 | forSequences = seq == null ? Collections.<SequenceI> emptyList() |
1227 | : Arrays.asList(seq); | |
1228 | } | |
1229 | 0 | return forSequences; |
1230 | } | |
1231 | ||
1232 | /** | |
1233 | * Add one annotation type to the 'Show Annotations' or 'Hide Annotations' | |
1234 | * menus. | |
1235 | * | |
1236 | * @param showOrHideMenu | |
1237 | * the menu to add to | |
1238 | * @param forSequences | |
1239 | * the sequences whose annotations may be shown or hidden | |
1240 | * @param calcId | |
1241 | * @param types | |
1242 | * the label to add | |
1243 | * @param allTypes | |
1244 | * if true this is a special label meaning 'All' | |
1245 | * @param actionIsShow | |
1246 | * if true, the select menu item action is to show the annotation | |
1247 | * type, else hide | |
1248 | */ | |
1249 | 94 | protected void addAnnotationTypeToShowHide(JMenu showOrHideMenu, |
1250 | final List<SequenceI> forSequences, String calcId, | |
1251 | final List<String> types, final boolean allTypes, | |
1252 | final boolean actionIsShow) | |
1253 | { | |
1254 | 94 | String label = types.toString(); // [a, b, c] |
1255 | 94 | label = label.substring(1, label.length() - 1); // a, b, c |
1256 | 94 | final JMenuItem item = new JMenuItem(label); |
1257 | 94 | item.setToolTipText(calcId); |
1258 | 94 | item.addActionListener(new ActionListener() |
1259 | { | |
1260 | 0 | @Override |
1261 | public void actionPerformed(ActionEvent e) | |
1262 | { | |
1263 | 0 | AlignmentUtils.showOrHideSequenceAnnotations(ap.getAlignment(), |
1264 | types, forSequences, allTypes, actionIsShow); | |
1265 | 0 | refresh(); |
1266 | } | |
1267 | }); | |
1268 | 94 | showOrHideMenu.add(item); |
1269 | } | |
1270 | ||
1271 | 0 | private void buildGroupURLMenu(SequenceGroup sg, List<String> groupLinks) |
1272 | { | |
1273 | ||
1274 | // TODO: usability: thread off the generation of group url content so root | |
1275 | // menu appears asap | |
1276 | // sequence only URLs | |
1277 | // ID/regex match URLs | |
1278 | 0 | JMenu groupLinksMenu = new JMenu( |
1279 | MessageManager.getString("action.group_link")); | |
1280 | // three types of url that might be created. | |
1281 | 0 | JMenu[] linkMenus = new JMenu[] { null, |
1282 | new JMenu(MessageManager.getString("action.ids")), | |
1283 | new JMenu(MessageManager.getString("action.sequences")), | |
1284 | new JMenu(MessageManager.getString("action.ids_sequences")) }; | |
1285 | ||
1286 | 0 | SequenceI[] seqs = ap.av.getSelectionAsNewSequence(); |
1287 | 0 | String[][] idandseqs = GroupUrlLink.formStrings(seqs); |
1288 | 0 | Hashtable<String, Object[]> commonDbrefs = new Hashtable<>(); |
1289 | 0 | for (int sq = 0; sq < seqs.length; sq++) |
1290 | { | |
1291 | ||
1292 | 0 | int start = seqs[sq].findPosition(sg.getStartRes()), |
1293 | end = seqs[sq].findPosition(sg.getEndRes()); | |
1294 | // just collect ids from dataset sequence | |
1295 | // TODO: check if IDs collected from selecton group intersects with the | |
1296 | // current selection, too | |
1297 | 0 | SequenceI sqi = seqs[sq]; |
1298 | 0 | while (sqi.getDatasetSequence() != null) |
1299 | { | |
1300 | 0 | sqi = sqi.getDatasetSequence(); |
1301 | } | |
1302 | 0 | List<DBRefEntry> dbr = sqi.getDBRefs(); |
1303 | 0 | int nd; |
1304 | 0 | if (dbr != null && (nd = dbr.size()) > 0) |
1305 | { | |
1306 | 0 | for (int d = 0; d < nd; d++) |
1307 | { | |
1308 | 0 | DBRefEntry e = dbr.get(d); |
1309 | 0 | String src = e.getSource(); // jalview.util.DBRefUtils.getCanonicalName(dbr[d].getSource()).toUpperCase(Locale.ROOT); |
1310 | 0 | Object[] sarray = commonDbrefs.get(src); |
1311 | 0 | if (sarray == null) |
1312 | { | |
1313 | 0 | sarray = new Object[2]; |
1314 | 0 | sarray[0] = new int[] { 0 }; |
1315 | 0 | sarray[1] = new String[seqs.length]; |
1316 | ||
1317 | 0 | commonDbrefs.put(src, sarray); |
1318 | } | |
1319 | ||
1320 | 0 | if (((String[]) sarray[1])[sq] == null) |
1321 | { | |
1322 | 0 | if (!e.hasMap() |
1323 | || (e.getMap().locateMappedRange(start, end) != null)) | |
1324 | { | |
1325 | 0 | ((String[]) sarray[1])[sq] = e.getAccessionId(); |
1326 | 0 | ((int[]) sarray[0])[0]++; |
1327 | } | |
1328 | } | |
1329 | } | |
1330 | } | |
1331 | } | |
1332 | // now create group links for all distinct ID/sequence sets. | |
1333 | 0 | boolean addMenu = false; // indicates if there are any group links to give |
1334 | // to user | |
1335 | 0 | for (String link : groupLinks) |
1336 | { | |
1337 | 0 | GroupUrlLink urlLink = null; |
1338 | 0 | try |
1339 | { | |
1340 | 0 | urlLink = new GroupUrlLink(link); |
1341 | } catch (Exception foo) | |
1342 | { | |
1343 | 0 | Console.error("Exception for GroupURLLink '" + link + "'", foo); |
1344 | 0 | continue; |
1345 | } | |
1346 | 0 | if (!urlLink.isValid()) |
1347 | { | |
1348 | 0 | Console.error(urlLink.getInvalidMessage()); |
1349 | 0 | continue; |
1350 | } | |
1351 | 0 | final String label = urlLink.getLabel(); |
1352 | 0 | boolean usingNames = false; |
1353 | // Now see which parts of the group apply for this URL | |
1354 | 0 | String ltarget = urlLink.getTarget(); // jalview.util.DBRefUtils.getCanonicalName(urlLink.getTarget()); |
1355 | 0 | Object[] idset = commonDbrefs.get(ltarget.toUpperCase(Locale.ROOT)); |
1356 | 0 | String[] seqstr, ids; // input to makeUrl |
1357 | 0 | if (idset != null) |
1358 | { | |
1359 | 0 | int numinput = ((int[]) idset[0])[0]; |
1360 | 0 | String[] allids = ((String[]) idset[1]); |
1361 | 0 | seqstr = new String[numinput]; |
1362 | 0 | ids = new String[numinput]; |
1363 | 0 | for (int sq = 0, idcount = 0; sq < seqs.length; sq++) |
1364 | { | |
1365 | 0 | if (allids[sq] != null) |
1366 | { | |
1367 | 0 | ids[idcount] = allids[sq]; |
1368 | 0 | seqstr[idcount++] = idandseqs[1][sq]; |
1369 | } | |
1370 | } | |
1371 | } | |
1372 | else | |
1373 | { | |
1374 | // just use the id/seq set | |
1375 | 0 | seqstr = idandseqs[1]; |
1376 | 0 | ids = idandseqs[0]; |
1377 | 0 | usingNames = true; |
1378 | } | |
1379 | // and try and make the groupURL! | |
1380 | ||
1381 | 0 | Object[] urlset = null; |
1382 | 0 | try |
1383 | { | |
1384 | 0 | urlset = urlLink.makeUrlStubs(ids, seqstr, |
1385 | "FromJalview" + System.currentTimeMillis(), false); | |
1386 | } catch (UrlStringTooLongException e) | |
1387 | { | |
1388 | } | |
1389 | 0 | if (urlset != null) |
1390 | { | |
1391 | 0 | int type = urlLink.getGroupURLType() & 3; |
1392 | // first two bits ofurlLink type bitfield are sequenceids and sequences | |
1393 | // TODO: FUTURE: ensure the groupURL menu structure can be generalised | |
1394 | 0 | addshowLink(linkMenus[type], |
1395 | 0 | label + (((type & 1) == 1) |
1396 | 0 | ? ("(" + (usingNames ? "Names" : ltarget) + ")") |
1397 | : ""), | |
1398 | urlLink, urlset); | |
1399 | 0 | addMenu = true; |
1400 | } | |
1401 | } | |
1402 | 0 | if (addMenu) |
1403 | { | |
1404 | 0 | groupLinksMenu = new JMenu( |
1405 | MessageManager.getString("action.group_link")); | |
1406 | 0 | for (int m = 0; m < linkMenus.length; m++) |
1407 | { | |
1408 | 0 | if (linkMenus[m] != null |
1409 | && linkMenus[m].getMenuComponentCount() > 0) | |
1410 | { | |
1411 | 0 | groupLinksMenu.add(linkMenus[m]); |
1412 | } | |
1413 | } | |
1414 | ||
1415 | 0 | groupMenu.add(groupLinksMenu); |
1416 | } | |
1417 | } | |
1418 | ||
1419 | /** | |
1420 | * DOCUMENT ME! | |
1421 | * | |
1422 | * @throws Exception | |
1423 | * DOCUMENT ME! | |
1424 | */ | |
1425 | 20 | private void jbInit() throws Exception |
1426 | { | |
1427 | 20 | groupMenu.setText(MessageManager.getString("label.selection")); |
1428 | 20 | groupName.setText(MessageManager.getString("label.name")); |
1429 | 20 | groupName.addActionListener(new ActionListener() |
1430 | { | |
1431 | 0 | @Override |
1432 | public void actionPerformed(ActionEvent e) | |
1433 | { | |
1434 | 0 | groupName_actionPerformed(); |
1435 | } | |
1436 | }); | |
1437 | 20 | sequenceMenu.setText(MessageManager.getString("label.sequence")); |
1438 | ||
1439 | 20 | JMenuItem sequenceName = new JMenuItem( |
1440 | MessageManager.getString("label.edit_name_description")); | |
1441 | 20 | sequenceName.addActionListener(new ActionListener() |
1442 | { | |
1443 | 0 | @Override |
1444 | public void actionPerformed(ActionEvent e) | |
1445 | { | |
1446 | 0 | sequenceName_actionPerformed(); |
1447 | } | |
1448 | }); | |
1449 | 20 | JMenuItem chooseAnnotations = new JMenuItem( |
1450 | MessageManager.getString("action.choose_annotations")); | |
1451 | 20 | chooseAnnotations.addActionListener(new ActionListener() |
1452 | { | |
1453 | 0 | @Override |
1454 | public void actionPerformed(ActionEvent e) | |
1455 | { | |
1456 | 0 | chooseAnnotations_actionPerformed(e); |
1457 | } | |
1458 | }); | |
1459 | 20 | JMenuItem sequenceDetails = new JMenuItem( |
1460 | MessageManager.getString("label.sequence_details")); | |
1461 | 20 | sequenceDetails.addActionListener(new ActionListener() |
1462 | { | |
1463 | 0 | @Override |
1464 | public void actionPerformed(ActionEvent e) | |
1465 | { | |
1466 | 0 | createSequenceDetailsReport(new SequenceI[] { sequence }); |
1467 | } | |
1468 | }); | |
1469 | 20 | JMenuItem sequenceSelDetails = new JMenuItem( |
1470 | MessageManager.getString("label.sequence_details")); | |
1471 | 20 | sequenceSelDetails.addActionListener(new ActionListener() |
1472 | { | |
1473 | 0 | @Override |
1474 | public void actionPerformed(ActionEvent e) | |
1475 | { | |
1476 | 0 | createSequenceDetailsReport(ap.av.getSequenceSelection()); |
1477 | } | |
1478 | }); | |
1479 | ||
1480 | 20 | unGroupMenuItem |
1481 | .setText(MessageManager.getString("action.remove_group")); | |
1482 | 20 | unGroupMenuItem.addActionListener(new ActionListener() |
1483 | { | |
1484 | 0 | @Override |
1485 | public void actionPerformed(ActionEvent e) | |
1486 | { | |
1487 | 0 | unGroupMenuItem_actionPerformed(); |
1488 | } | |
1489 | }); | |
1490 | 20 | createGroupMenuItem |
1491 | .setText(MessageManager.getString("action.create_group")); | |
1492 | 20 | createGroupMenuItem.addActionListener(new ActionListener() |
1493 | { | |
1494 | 0 | @Override |
1495 | public void actionPerformed(ActionEvent e) | |
1496 | { | |
1497 | 0 | createGroupMenuItem_actionPerformed(); |
1498 | } | |
1499 | }); | |
1500 | ||
1501 | 20 | JMenuItem outline = new JMenuItem( |
1502 | MessageManager.getString("action.border_colour")); | |
1503 | 20 | outline.addActionListener(new ActionListener() |
1504 | { | |
1505 | 0 | @Override |
1506 | public void actionPerformed(ActionEvent e) | |
1507 | { | |
1508 | 0 | outline_actionPerformed(); |
1509 | } | |
1510 | }); | |
1511 | 20 | showBoxes.setText(MessageManager.getString("action.boxes")); |
1512 | 20 | showBoxes.setState(true); |
1513 | 20 | showBoxes.addActionListener(new ActionListener() |
1514 | { | |
1515 | 0 | @Override |
1516 | public void actionPerformed(ActionEvent e) | |
1517 | { | |
1518 | 0 | showBoxes_actionPerformed(); |
1519 | } | |
1520 | }); | |
1521 | 20 | showText.setText(MessageManager.getString("action.text")); |
1522 | 20 | showText.setState(true); |
1523 | 20 | showText.addActionListener(new ActionListener() |
1524 | { | |
1525 | 0 | @Override |
1526 | public void actionPerformed(ActionEvent e) | |
1527 | { | |
1528 | 0 | showText_actionPerformed(); |
1529 | } | |
1530 | }); | |
1531 | 20 | showColourText.setText(MessageManager.getString("label.colour_text")); |
1532 | 20 | showColourText.addActionListener(new ActionListener() |
1533 | { | |
1534 | 0 | @Override |
1535 | public void actionPerformed(ActionEvent e) | |
1536 | { | |
1537 | 0 | showColourText_actionPerformed(); |
1538 | } | |
1539 | }); | |
1540 | 20 | displayNonconserved |
1541 | .setText(MessageManager.getString("label.show_non_conserved")); | |
1542 | 20 | displayNonconserved.setState(true); |
1543 | 20 | displayNonconserved.addActionListener(new ActionListener() |
1544 | { | |
1545 | 0 | @Override |
1546 | public void actionPerformed(ActionEvent e) | |
1547 | { | |
1548 | 0 | showNonconserved_actionPerformed(); |
1549 | } | |
1550 | }); | |
1551 | 20 | editMenu.setText(MessageManager.getString("action.edit")); |
1552 | 20 | JMenuItem cut = new JMenuItem(MessageManager.getString("action.cut")); |
1553 | 20 | cut.addActionListener(new ActionListener() |
1554 | { | |
1555 | 0 | @Override |
1556 | public void actionPerformed(ActionEvent e) | |
1557 | { | |
1558 | 0 | cut_actionPerformed(); |
1559 | } | |
1560 | }); | |
1561 | 20 | JMenuItem justifyLeftMenuItem = new JMenuItem( |
1562 | MessageManager.getString("action.left_justify")); | |
1563 | 20 | justifyLeftMenuItem.addActionListener(new ActionListener() |
1564 | { | |
1565 | ||
1566 | 0 | @Override |
1567 | public void actionPerformed(ActionEvent e) | |
1568 | { | |
1569 | 0 | ap.alignFrame.avc.justify_Region(true); |
1570 | } | |
1571 | }); | |
1572 | 20 | JMenuItem justifyRightMenuItem = new JMenuItem( |
1573 | MessageManager.getString("action.right_justify")); | |
1574 | 20 | justifyRightMenuItem.addActionListener(new ActionListener() |
1575 | { | |
1576 | ||
1577 | 0 | @Override |
1578 | public void actionPerformed(ActionEvent e) | |
1579 | { | |
1580 | 0 | ap.alignFrame.avc.justify_Region(false); |
1581 | } | |
1582 | }); | |
1583 | ||
1584 | 20 | upperCase.setText(MessageManager.getString("label.to_upper_case")); |
1585 | 20 | upperCase.addActionListener(new ActionListener() |
1586 | { | |
1587 | 0 | @Override |
1588 | public void actionPerformed(ActionEvent e) | |
1589 | { | |
1590 | 0 | changeCase(e); |
1591 | } | |
1592 | }); | |
1593 | 20 | JMenuItem copy = new JMenuItem(MessageManager.getString("action.copy")); |
1594 | 20 | copy.addActionListener(new ActionListener() |
1595 | { | |
1596 | 0 | @Override |
1597 | public void actionPerformed(ActionEvent e) | |
1598 | { | |
1599 | 0 | copy_actionPerformed(); |
1600 | } | |
1601 | }); | |
1602 | 20 | lowerCase.setText(MessageManager.getString("label.to_lower_case")); |
1603 | 20 | lowerCase.addActionListener(new ActionListener() |
1604 | { | |
1605 | 0 | @Override |
1606 | public void actionPerformed(ActionEvent e) | |
1607 | { | |
1608 | 0 | changeCase(e); |
1609 | } | |
1610 | }); | |
1611 | 20 | toggle.setText(MessageManager.getString("label.toggle_case")); |
1612 | 20 | toggle.addActionListener(new ActionListener() |
1613 | { | |
1614 | 0 | @Override |
1615 | public void actionPerformed(ActionEvent e) | |
1616 | { | |
1617 | 0 | changeCase(e); |
1618 | } | |
1619 | }); | |
1620 | 20 | outputMenu.setText( |
1621 | MessageManager.getString("label.out_to_textbox") + "..."); | |
1622 | 20 | seqShowAnnotationsMenu |
1623 | .setText(MessageManager.getString("label.show_annotations")); | |
1624 | 20 | seqHideAnnotationsMenu |
1625 | .setText(MessageManager.getString("label.hide_annotations")); | |
1626 | 20 | groupShowAnnotationsMenu |
1627 | .setText(MessageManager.getString("label.show_annotations")); | |
1628 | 20 | groupHideAnnotationsMenu |
1629 | .setText(MessageManager.getString("label.hide_annotations")); | |
1630 | 20 | groupShowAutoCalculatedAnnotations.setText(MessageManager |
1631 | .getString("label.group_show_auto_calculated_annotations")); | |
1632 | 20 | groupHideAutoCalculatedAnnotations.setText(MessageManager |
1633 | .getString("label.group_hide_auto_calculated_annotations")); | |
1634 | 20 | JMenuItem sequenceFeature = new JMenuItem( |
1635 | MessageManager.getString("label.create_sequence_feature")); | |
1636 | 20 | sequenceFeature.addActionListener(new ActionListener() |
1637 | { | |
1638 | 0 | @Override |
1639 | public void actionPerformed(ActionEvent e) | |
1640 | { | |
1641 | 0 | sequenceFeature_actionPerformed(); |
1642 | } | |
1643 | }); | |
1644 | 20 | editGroupMenu.setText(MessageManager.getString("label.group")); |
1645 | 20 | chooseStructure.setText( |
1646 | MessageManager.getString("label.show_pdbstruct_dialog")); | |
1647 | 20 | chooseStructure.addActionListener(new ActionListener() |
1648 | { | |
1649 | 0 | @Override |
1650 | public void actionPerformed(ActionEvent actionEvent) | |
1651 | { | |
1652 | 0 | SequenceI[] selectedSeqs = new SequenceI[] { sequence }; |
1653 | 0 | if (ap.av.getSelectionGroup() != null) |
1654 | { | |
1655 | 0 | selectedSeqs = ap.av.getSequenceSelection(); |
1656 | } | |
1657 | 0 | new StructureChooser(selectedSeqs, sequence, ap); |
1658 | } | |
1659 | }); | |
1660 | ||
1661 | 20 | rnaStructureMenu |
1662 | .setText(MessageManager.getString("label.view_rna_structure")); | |
1663 | ||
1664 | // colStructureMenu.setText("Colour By Structure"); | |
1665 | 20 | JMenuItem editSequence = new JMenuItem( |
1666 | MessageManager.getString("label.edit_sequence") + "..."); | |
1667 | 20 | editSequence.addActionListener(new ActionListener() |
1668 | { | |
1669 | 0 | @Override |
1670 | public void actionPerformed(ActionEvent actionEvent) | |
1671 | { | |
1672 | 0 | editSequence_actionPerformed(); |
1673 | } | |
1674 | }); | |
1675 | 20 | makeReferenceSeq.setText( |
1676 | MessageManager.getString("label.mark_as_representative")); | |
1677 | 20 | makeReferenceSeq.addActionListener(new ActionListener() |
1678 | { | |
1679 | ||
1680 | 0 | @Override |
1681 | public void actionPerformed(ActionEvent actionEvent) | |
1682 | { | |
1683 | 0 | makeReferenceSeq_actionPerformed(actionEvent); |
1684 | ||
1685 | } | |
1686 | }); | |
1687 | ||
1688 | 20 | groupMenu.add(sequenceSelDetails); |
1689 | 20 | add(groupMenu); |
1690 | 20 | add(sequenceMenu); |
1691 | 20 | add(rnaStructureMenu); |
1692 | 20 | add(chooseStructure); |
1693 | 20 | if (forIdPanel) |
1694 | { | |
1695 | 20 | JMenuItem hideInsertions = new JMenuItem( |
1696 | MessageManager.getString("label.hide_insertions")); | |
1697 | 20 | hideInsertions.addActionListener(new ActionListener() |
1698 | { | |
1699 | ||
1700 | 0 | @Override |
1701 | public void actionPerformed(ActionEvent e) | |
1702 | { | |
1703 | 0 | hideInsertions_actionPerformed(e); |
1704 | } | |
1705 | }); | |
1706 | 20 | add(hideInsertions); |
1707 | } | |
1708 | // annotations configuration panel suppressed for now | |
1709 | // groupMenu.add(chooseAnnotations); | |
1710 | ||
1711 | /* | |
1712 | * Add show/hide annotations to the Sequence menu, and to the Selection menu | |
1713 | * (if a selection group is in force). | |
1714 | */ | |
1715 | 20 | sequenceMenu.add(seqShowAnnotationsMenu); |
1716 | 20 | sequenceMenu.add(seqHideAnnotationsMenu); |
1717 | 20 | sequenceMenu.add(seqAddReferenceAnnotations); |
1718 | 20 | groupMenu.add(groupShowAnnotationsMenu); |
1719 | 20 | groupMenu.add(groupHideAnnotationsMenu); |
1720 | 20 | groupMenu.add(groupAddReferenceAnnotations); |
1721 | 20 | groupMenu.add(groupShowAutoCalculatedAnnotations); |
1722 | 20 | groupMenu.add(groupHideAutoCalculatedAnnotations); |
1723 | 20 | groupMenu.add(editMenu); |
1724 | 20 | groupMenu.add(outputMenu); |
1725 | 20 | groupMenu.add(sequenceFeature); |
1726 | 20 | groupMenu.add(createGroupMenuItem); |
1727 | 20 | groupMenu.add(unGroupMenuItem); |
1728 | 20 | groupMenu.add(editGroupMenu); |
1729 | 20 | sequenceMenu.add(sequenceName); |
1730 | 20 | sequenceMenu.add(sequenceDetails); |
1731 | 20 | sequenceMenu.add(makeReferenceSeq); |
1732 | ||
1733 | 20 | initColourMenu(); |
1734 | 20 | buildColourMenu(); |
1735 | ||
1736 | 20 | editMenu.add(copy); |
1737 | 20 | editMenu.add(cut); |
1738 | 20 | editMenu.add(justifyLeftMenuItem); |
1739 | 20 | editMenu.add(justifyRightMenuItem); |
1740 | 20 | editMenu.add(editSequence); |
1741 | 20 | editMenu.add(upperCase); |
1742 | 20 | editMenu.add(lowerCase); |
1743 | 20 | editMenu.add(toggle); |
1744 | 20 | editGroupMenu.add(groupName); |
1745 | 20 | editGroupMenu.add(colourMenu); |
1746 | 20 | editGroupMenu.add(showBoxes); |
1747 | 20 | editGroupMenu.add(showText); |
1748 | 20 | editGroupMenu.add(showColourText); |
1749 | 20 | editGroupMenu.add(outline); |
1750 | 20 | editGroupMenu.add(displayNonconserved); |
1751 | } | |
1752 | ||
1753 | /** | |
1754 | * Constructs the entries for the colour menu | |
1755 | */ | |
1756 | 20 | protected void initColourMenu() |
1757 | { | |
1758 | 20 | colourMenu.setText(MessageManager.getString("label.group_colour")); |
1759 | 20 | textColour.setText(MessageManager.getString("label.text_colour")); |
1760 | 20 | textColour.addActionListener(new ActionListener() |
1761 | { | |
1762 | 0 | @Override |
1763 | public void actionPerformed(ActionEvent e) | |
1764 | { | |
1765 | 0 | textColour_actionPerformed(); |
1766 | } | |
1767 | }); | |
1768 | ||
1769 | 20 | abovePIDColour.setText( |
1770 | MessageManager.getString("label.above_identity_threshold")); | |
1771 | 20 | abovePIDColour.addActionListener(new ActionListener() |
1772 | { | |
1773 | 0 | @Override |
1774 | public void actionPerformed(ActionEvent e) | |
1775 | { | |
1776 | 0 | abovePIDColour_actionPerformed(abovePIDColour.isSelected()); |
1777 | } | |
1778 | }); | |
1779 | ||
1780 | 20 | modifyPID.setText( |
1781 | MessageManager.getString("label.modify_identity_threshold")); | |
1782 | 20 | modifyPID.addActionListener(new ActionListener() |
1783 | { | |
1784 | 0 | @Override |
1785 | public void actionPerformed(ActionEvent e) | |
1786 | { | |
1787 | 0 | modifyPID_actionPerformed(); |
1788 | } | |
1789 | }); | |
1790 | ||
1791 | 20 | conservationMenuItem |
1792 | .setText(MessageManager.getString("action.by_conservation")); | |
1793 | 20 | conservationMenuItem.addActionListener(new ActionListener() |
1794 | { | |
1795 | 0 | @Override |
1796 | public void actionPerformed(ActionEvent e) | |
1797 | { | |
1798 | 0 | conservationMenuItem_actionPerformed( |
1799 | conservationMenuItem.isSelected()); | |
1800 | } | |
1801 | }); | |
1802 | ||
1803 | 20 | byConsensusSecondaryStructureMenuItem.setText(MessageManager |
1804 | .getString("action.by_secondary_structure_conservation")); | |
1805 | 20 | byConsensusSecondaryStructureMenuItem |
1806 | .addActionListener(new ActionListener() | |
1807 | { | |
1808 | 0 | @Override |
1809 | public void actionPerformed(ActionEvent e) | |
1810 | { | |
1811 | 0 | colourByConsensusSecondaryStructureMenuItem_actionPerformed( |
1812 | byConsensusSecondaryStructureMenuItem.isSelected()); | |
1813 | } | |
1814 | }); | |
1815 | ||
1816 | 20 | annotationColour = new JRadioButtonMenuItem( |
1817 | MessageManager.getString("action.by_annotation")); | |
1818 | 20 | annotationColour.setName(ResidueColourScheme.ANNOTATION_COLOUR); |
1819 | 20 | annotationColour.setEnabled(false); |
1820 | 20 | annotationColour.setToolTipText( |
1821 | MessageManager.getString("label.by_annotation_tooltip")); | |
1822 | ||
1823 | 20 | modifyConservation.setText(MessageManager |
1824 | .getString("label.modify_conservation_threshold")); | |
1825 | 20 | modifyConservation.addActionListener(new ActionListener() |
1826 | { | |
1827 | 0 | @Override |
1828 | public void actionPerformed(ActionEvent e) | |
1829 | { | |
1830 | 0 | modifyConservation_actionPerformed(); |
1831 | } | |
1832 | }); | |
1833 | ||
1834 | 20 | modifyConsensusSecondaryStructureThreshold |
1835 | .setText(MessageManager.getString( | |
1836 | "label.modify_secondary_structure_conservation_threshold")); | |
1837 | 20 | modifyConsensusSecondaryStructureThreshold |
1838 | .addActionListener(new ActionListener() | |
1839 | { | |
1840 | 0 | @Override |
1841 | public void actionPerformed(ActionEvent e) | |
1842 | { | |
1843 | 0 | modifyConsensusSecondaryStructureThreshold_actionPerformed(); |
1844 | } | |
1845 | }); | |
1846 | } | |
1847 | ||
1848 | /** | |
1849 | * Builds the group colour sub-menu, including any user-defined colours which | |
1850 | * were loaded at startup or during the Jalview session | |
1851 | */ | |
1852 | 20 | protected void buildColourMenu() |
1853 | { | |
1854 | 20 | SequenceGroup sg = ap.av.getSelectionGroup(); |
1855 | 20 | if (sg == null) |
1856 | { | |
1857 | /* | |
1858 | * popup menu with no sequence group scope | |
1859 | */ | |
1860 | 16 | return; |
1861 | } | |
1862 | 4 | colourMenu.removeAll(); |
1863 | 4 | colourMenu.add(textColour); |
1864 | 4 | colourMenu.addSeparator(); |
1865 | ||
1866 | 4 | ButtonGroup bg = ColourMenuHelper.addMenuItems(colourMenu, this, sg, |
1867 | false); | |
1868 | 4 | bg.add(annotationColour); |
1869 | 4 | colourMenu.add(annotationColour); |
1870 | ||
1871 | 4 | colourMenu.addSeparator(); |
1872 | 4 | colourMenu.add(conservationMenuItem); |
1873 | 4 | colourMenu.add(modifyConservation); |
1874 | 4 | colourMenu.add(byConsensusSecondaryStructureMenuItem); |
1875 | 4 | colourMenu.add(modifyConsensusSecondaryStructureThreshold); |
1876 | 4 | colourMenu.add(abovePIDColour); |
1877 | 4 | colourMenu.add(modifyPID); |
1878 | } | |
1879 | ||
1880 | 0 | protected void modifyConservation_actionPerformed() |
1881 | { | |
1882 | 0 | SequenceGroup sg = getGroup(); |
1883 | 0 | if (sg.cs != null) |
1884 | { | |
1885 | 0 | SliderPanel.setConservationSlider(ap, sg.cs, sg.getName()); |
1886 | 0 | SliderPanel.showConservationSlider(); |
1887 | } | |
1888 | } | |
1889 | ||
1890 | 0 | protected void modifyConsensusSecondaryStructureThreshold_actionPerformed() |
1891 | { | |
1892 | 0 | SequenceGroup sg = getGroup(); |
1893 | 0 | if (sg.cs != null) |
1894 | { | |
1895 | 0 | SliderPanel.setConsensusSecondaryStructureSlider(ap, sg.cs, |
1896 | sg.getName()); | |
1897 | 0 | SliderPanel.showConsensusSecondaryStructureSlider(); |
1898 | } | |
1899 | } | |
1900 | ||
1901 | 0 | protected void modifyPID_actionPerformed() |
1902 | { | |
1903 | 0 | SequenceGroup sg = getGroup(); |
1904 | 0 | if (sg.cs != null) |
1905 | { | |
1906 | // int threshold = SliderPanel.setPIDSliderSource(ap, sg.cs, getGroup() | |
1907 | // .getName()); | |
1908 | // sg.cs.setThreshold(threshold, ap.av.isIgnoreGapsConsensus()); | |
1909 | 0 | SliderPanel.setPIDSliderSource(ap, sg.cs, getGroup().getName()); |
1910 | 0 | SliderPanel.showPIDSlider(); |
1911 | } | |
1912 | } | |
1913 | ||
1914 | /** | |
1915 | * Check for any annotations on the underlying dataset sequences (for the | |
1916 | * current selection group) which are not 'on the alignment'.If any are found, | |
1917 | * enable the option to add them to the alignment. The criteria for 'on the | |
1918 | * alignment' is finding an alignment annotation on the alignment, matched on | |
1919 | * calcId, label and sequenceRef. | |
1920 | * | |
1921 | * A tooltip is also constructed that displays the source (calcId) and type | |
1922 | * (label) of the annotations that can be added. | |
1923 | * | |
1924 | * @param menuItem | |
1925 | * @param forSequences | |
1926 | */ | |
1927 | 46 | protected void configureReferenceAnnotationsMenu(JMenuItem menuItem, |
1928 | List<SequenceI> forSequences) | |
1929 | { | |
1930 | 46 | menuItem.setEnabled(false); |
1931 | ||
1932 | /* | |
1933 | * Temporary store to hold distinct calcId / type pairs for the tooltip. | |
1934 | * Using TreeMap means calcIds are shown in alphabetical order. | |
1935 | */ | |
1936 | 46 | SortedMap<String, String> tipEntries = new TreeMap<>(); |
1937 | 46 | final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>(); |
1938 | 46 | AlignmentI al = this.ap.av.getAlignment(); |
1939 | 46 | AlignmentUtils.findAddableReferenceAnnotations(forSequences, tipEntries, |
1940 | candidates, al); | |
1941 | 46 | if (!candidates.isEmpty()) |
1942 | { | |
1943 | 2 | StringBuilder tooltip = new StringBuilder(64); |
1944 | 2 | tooltip.append(MessageManager.getString("label.add_annotations_for")); |
1945 | ||
1946 | /* | |
1947 | * Found annotations that could be added. Enable the menu item, and | |
1948 | * configure its tooltip and action. | |
1949 | */ | |
1950 | 2 | menuItem.setEnabled(true); |
1951 | 2 | for (String calcId : tipEntries.keySet()) |
1952 | { | |
1953 | 4 | tooltip.append("<br/>" + calcId + "/" + tipEntries.get(calcId)); |
1954 | } | |
1955 | 2 | String tooltipText = JvSwingUtils.wrapTooltip(true, |
1956 | tooltip.toString()); | |
1957 | 2 | menuItem.setToolTipText(tooltipText); |
1958 | ||
1959 | 2 | menuItem.addActionListener(new ActionListener() |
1960 | { | |
1961 | 0 | @Override |
1962 | public void actionPerformed(ActionEvent e) | |
1963 | { | |
1964 | 0 | addReferenceAnnotations_actionPerformed(candidates); |
1965 | } | |
1966 | }); | |
1967 | } | |
1968 | } | |
1969 | ||
1970 | /** | |
1971 | * Add annotations to the sequences and to the alignment. | |
1972 | * | |
1973 | * @param candidates | |
1974 | * a map whose keys are sequences on the alignment, and values a list | |
1975 | * of annotations to add to each sequence | |
1976 | */ | |
1977 | 0 | protected void addReferenceAnnotations_actionPerformed( |
1978 | Map<SequenceI, List<AlignmentAnnotation>> candidates) | |
1979 | { | |
1980 | 0 | final AlignmentI alignment = this.ap.getAlignment(); |
1981 | 0 | AlignmentUtils.addReferenceAnnotations(candidates, alignment, null); |
1982 | ||
1983 | 0 | if (AlignmentUtils.isSSAnnotationPresent(candidates)) |
1984 | { | |
1985 | ||
1986 | 0 | restartSSConsensusWorker(); |
1987 | 0 | ap.validateAnnotationDimensions(true); |
1988 | 0 | ap.fontChanged(); |
1989 | 0 | ap.av.alignmentChanged(ap); |
1990 | 0 | ap.adjustAnnotationHeight(); |
1991 | 0 | restartSSConsensusWorker(); |
1992 | //ap.alignFrame.getViewport().getCalcManager().restartWorkers(); | |
1993 | } | |
1994 | } | |
1995 | ||
1996 | 0 | private void restartSSConsensusWorker() |
1997 | { | |
1998 | ||
1999 | 0 | List<AlignCalcWorkerI> workers = ap.alignFrame.getViewport() |
2000 | .getCalcManager().getRegisteredWorkersOfClass( | |
2001 | SecondaryStructureConsensusThread.class); | |
2002 | 0 | if (!workers.isEmpty()) |
2003 | { | |
2004 | ||
2005 | 0 | ap.alignFrame.getViewport().getCalcManager() |
2006 | .startWorker(workers.remove(0)); | |
2007 | ||
2008 | } | |
2009 | ||
2010 | } | |
2011 | ||
2012 | 0 | protected void makeReferenceSeq_actionPerformed(ActionEvent actionEvent) |
2013 | { | |
2014 | 0 | if (!ap.av.getAlignment().hasSeqrep()) |
2015 | { | |
2016 | // initialise the display flags so the user sees something happen | |
2017 | 0 | ap.av.setDisplayReferenceSeq(true); |
2018 | 0 | ap.av.setColourByReferenceSeq(true); |
2019 | 0 | ap.av.getAlignment().setSeqrep(sequence); |
2020 | } | |
2021 | else | |
2022 | { | |
2023 | 0 | if (ap.av.getAlignment().getSeqrep() == sequence) |
2024 | { | |
2025 | 0 | ap.av.getAlignment().setSeqrep(null); |
2026 | } | |
2027 | else | |
2028 | { | |
2029 | 0 | ap.av.getAlignment().setSeqrep(sequence); |
2030 | } | |
2031 | } | |
2032 | 0 | refresh(); |
2033 | } | |
2034 | ||
2035 | 3 | protected void hideInsertions_actionPerformed(ActionEvent actionEvent) |
2036 | { | |
2037 | 3 | HiddenColumns hidden = ap.av.getAlignment().getHiddenColumns(); |
2038 | 3 | BitSet inserts = new BitSet(); |
2039 | ||
2040 | 3 | boolean markedPopup = false; |
2041 | // mark inserts in current selection | |
2042 | 3 | if (ap.av.getSelectionGroup() != null) |
2043 | { | |
2044 | // mark just the columns in the selection group to be hidden | |
2045 | 1 | inserts.set(ap.av.getSelectionGroup().getStartRes(), |
2046 | ap.av.getSelectionGroup().getEndRes() + 1); // TODO why +1? | |
2047 | ||
2048 | // now clear columns without gaps | |
2049 | 1 | for (SequenceI sq : ap.av.getSelectionGroup().getSequences()) |
2050 | { | |
2051 | 2 | if (sq == sequence) |
2052 | { | |
2053 | 1 | markedPopup = true; |
2054 | } | |
2055 | 2 | inserts.and(sq.getInsertionsAsBits()); |
2056 | } | |
2057 | 1 | hidden.clearAndHideColumns(inserts, |
2058 | ap.av.getSelectionGroup().getStartRes(), | |
2059 | ap.av.getSelectionGroup().getEndRes()); | |
2060 | } | |
2061 | ||
2062 | // now mark for sequence under popup if we haven't already done it | |
2063 | 2 | else if (!markedPopup && sequence != null) |
2064 | { | |
2065 | 2 | inserts.or(sequence.getInsertionsAsBits()); |
2066 | ||
2067 | // and set hidden columns accordingly | |
2068 | 2 | hidden.hideColumns(inserts); |
2069 | } | |
2070 | 3 | refresh(); |
2071 | } | |
2072 | ||
2073 | 0 | protected void sequenceSelectionDetails_actionPerformed() |
2074 | { | |
2075 | 0 | createSequenceDetailsReport(ap.av.getSequenceSelection()); |
2076 | } | |
2077 | ||
2078 | 0 | public void createSequenceDetailsReport(SequenceI[] sequences) |
2079 | { | |
2080 | 0 | StringBuilder contents = new StringBuilder(128); |
2081 | 0 | contents.append("<html><body>"); |
2082 | 0 | for (SequenceI seq : sequences) |
2083 | { | |
2084 | 0 | contents.append("<p><h2>" + MessageManager.formatMessage( |
2085 | "label.create_sequence_details_report_annotation_for", | |
2086 | new Object[] | |
2087 | { seq.getDisplayId(true) }) + "</h2></p>\n<p>"); | |
2088 | 0 | new SequenceAnnotationReport(false).createSequenceAnnotationReport( |
2089 | contents, seq, true, true, ap.getSeqPanel().seqCanvas.fr); | |
2090 | 0 | contents.append("</p>"); |
2091 | } | |
2092 | 0 | contents.append("</body></html>"); |
2093 | 0 | String report = contents.toString(); |
2094 | ||
2095 | 0 | JInternalFrame frame; |
2096 | 0 | if (Platform.isJS()) |
2097 | { | |
2098 | 0 | JLabel textLabel = new JLabel(); |
2099 | 0 | textLabel.setText(report); |
2100 | 0 | textLabel.setBackground(Color.WHITE); |
2101 | 0 | JPanel pane = new JPanel(new BorderLayout()); |
2102 | 0 | pane.setOpaque(true); |
2103 | 0 | pane.setBackground(Color.WHITE); |
2104 | 0 | pane.add(textLabel, BorderLayout.NORTH); |
2105 | 0 | frame = new JInternalFrame(); |
2106 | 0 | frame.setFrameIcon(null); |
2107 | 0 | frame.getContentPane().add(new JScrollPane(pane)); |
2108 | } | |
2109 | else | |
2110 | /** | |
2111 | * Java only | |
2112 | * | |
2113 | * @j2sIgnore | |
2114 | */ | |
2115 | { | |
2116 | 0 | CutAndPasteHtmlTransfer cap = new CutAndPasteHtmlTransfer(); |
2117 | 0 | cap.setText(report); |
2118 | 0 | frame = cap; |
2119 | } | |
2120 | ||
2121 | 0 | Desktop.addInternalFrame(frame, |
2122 | MessageManager.formatMessage("label.sequence_details_for", | |
2123 | 0 | (sequences.length == 1 ? new Object[] |
2124 | { sequences[0].getDisplayId(true) } | |
2125 | : new Object[] | |
2126 | { MessageManager | |
2127 | .getString("label.selection") })), | |
2128 | 500, 400); | |
2129 | } | |
2130 | ||
2131 | 0 | protected void showNonconserved_actionPerformed() |
2132 | { | |
2133 | 0 | getGroup().setShowNonconserved(displayNonconserved.isSelected()); |
2134 | 0 | refresh(); |
2135 | } | |
2136 | ||
2137 | /** | |
2138 | * call to refresh view after settings change | |
2139 | */ | |
2140 | 12 | void refresh() |
2141 | { | |
2142 | 12 | ap.updateAnnotation(); |
2143 | // removed paintAlignment(true) here: | |
2144 | // updateAnnotation calls paintAlignment already, so don't need to call | |
2145 | // again | |
2146 | ||
2147 | 12 | PaintRefresher.Refresh(this, ap.av.getSequenceSetId()); |
2148 | } | |
2149 | ||
2150 | /* | |
2151 | * protected void covariationColour_actionPerformed() { getGroup().cs = new | |
2152 | * CovariationColourScheme(sequence.getAnnotation()[0]); refresh(); } | |
2153 | */ | |
2154 | /** | |
2155 | * DOCUMENT ME! | |
2156 | * | |
2157 | * @param selected | |
2158 | * | |
2159 | * @param e | |
2160 | * DOCUMENT ME! | |
2161 | */ | |
2162 | 3 | public void abovePIDColour_actionPerformed(boolean selected) |
2163 | { | |
2164 | 3 | SequenceGroup sg = getGroup(); |
2165 | 3 | if (sg.cs == null) |
2166 | { | |
2167 | 0 | return; |
2168 | } | |
2169 | ||
2170 | 3 | if (selected) |
2171 | { | |
2172 | 3 | sg.cs.setConsensus(AAFrequency.calculate( |
2173 | sg.getSequences(ap.av.getHiddenRepSequences()), | |
2174 | sg.getStartRes(), sg.getEndRes() + 1)); | |
2175 | ||
2176 | 3 | int threshold = SliderPanel.setPIDSliderSource(ap, |
2177 | sg.getGroupColourScheme(), getGroup().getName()); | |
2178 | ||
2179 | 3 | sg.cs.setThreshold(threshold, ap.av.isIgnoreGapsConsensus()); |
2180 | ||
2181 | 3 | SliderPanel.showPIDSlider(); |
2182 | } | |
2183 | else | |
2184 | // remove PIDColouring | |
2185 | { | |
2186 | 0 | sg.cs.setThreshold(0, ap.av.isIgnoreGapsConsensus()); |
2187 | 0 | SliderPanel.hidePIDSlider(); |
2188 | } | |
2189 | 3 | modifyPID.setEnabled(selected); |
2190 | ||
2191 | 3 | refresh(); |
2192 | } | |
2193 | ||
2194 | /** | |
2195 | * Open a panel where the user can choose which types of sequence annotation | |
2196 | * to show or hide. | |
2197 | * | |
2198 | * @param e | |
2199 | */ | |
2200 | 0 | protected void chooseAnnotations_actionPerformed(ActionEvent e) |
2201 | { | |
2202 | // todo correct way to guard against opening a duplicate panel? | |
2203 | 0 | new AnnotationChooser(ap); |
2204 | } | |
2205 | ||
2206 | /** | |
2207 | * DOCUMENT ME! | |
2208 | * | |
2209 | * @param e | |
2210 | * DOCUMENT ME! | |
2211 | */ | |
2212 | 3 | public void conservationMenuItem_actionPerformed(boolean selected) |
2213 | { | |
2214 | 3 | SequenceGroup sg = getGroup(); |
2215 | 3 | if (sg.cs == null) |
2216 | { | |
2217 | 0 | return; |
2218 | } | |
2219 | ||
2220 | 3 | if (selected) |
2221 | { | |
2222 | // JBPNote: Conservation name shouldn't be i18n translated | |
2223 | 3 | Conservation c = new Conservation("Group", |
2224 | sg.getSequences(ap.av.getHiddenRepSequences()), | |
2225 | sg.getStartRes(), sg.getEndRes() + 1); | |
2226 | ||
2227 | 3 | c.calculate(); |
2228 | 3 | c.verdict(false, ap.av.getConsPercGaps()); |
2229 | 3 | sg.cs.setConservation(c); |
2230 | ||
2231 | 3 | SliderPanel.setConservationSlider(ap, sg.getGroupColourScheme(), |
2232 | sg.getName()); | |
2233 | 3 | SliderPanel.showConservationSlider(); |
2234 | } | |
2235 | else | |
2236 | // remove ConservationColouring | |
2237 | { | |
2238 | 0 | sg.cs.setConservation(null); |
2239 | 0 | SliderPanel.hideConservationSlider(); |
2240 | } | |
2241 | 3 | modifyConservation.setEnabled(selected); |
2242 | ||
2243 | 3 | refresh(); |
2244 | } | |
2245 | ||
2246 | 0 | public void colourByConsensusSecondaryStructureMenuItem_actionPerformed( |
2247 | boolean selected) | |
2248 | { | |
2249 | 0 | SequenceGroup sg = getGroup(); |
2250 | 0 | if (sg.cs == null) |
2251 | { | |
2252 | 0 | return; |
2253 | } | |
2254 | ||
2255 | 0 | if (selected) |
2256 | { | |
2257 | ||
2258 | 0 | sg.cs.setConsensusSecondaryStructureColouring(selected); |
2259 | ||
2260 | 0 | SliderPanel.setConsensusSecondaryStructureSlider(ap, |
2261 | sg.getGroupColourScheme(), sg.getName()); | |
2262 | 0 | SliderPanel.showConsensusSecondaryStructureSlider(); |
2263 | } | |
2264 | else | |
2265 | // remove ConsensusSecondaryStructureColouring | |
2266 | { | |
2267 | 0 | sg.cs.setConsensusSecondaryStructureColouring(selected); |
2268 | 0 | SliderPanel.hideConsensusSecondaryStructureSlider(); |
2269 | } | |
2270 | 0 | modifyConsensusSecondaryStructureThreshold.setEnabled(selected); |
2271 | ||
2272 | 0 | refresh(); |
2273 | } | |
2274 | ||
2275 | /** | |
2276 | * Shows a dialog where group name and description may be edited | |
2277 | */ | |
2278 | 0 | protected void groupName_actionPerformed() |
2279 | { | |
2280 | 0 | SequenceGroup sg = getGroup(); |
2281 | 0 | EditNameDialog dialog = new EditNameDialog(sg.getName(), |
2282 | sg.getDescription(), | |
2283 | MessageManager.getString("label.group_name"), | |
2284 | MessageManager.getString("label.group_description")); | |
2285 | 0 | dialog.showDialog(ap.alignFrame, |
2286 | MessageManager.getString("label.edit_group_name_description"), | |
2287 | () -> { | |
2288 | 0 | sg.setName(dialog.getName()); |
2289 | 0 | sg.setDescription(dialog.getDescription()); |
2290 | 0 | refresh(); |
2291 | }); | |
2292 | } | |
2293 | ||
2294 | /** | |
2295 | * Get selection group - adding it to the alignment if necessary. | |
2296 | * | |
2297 | * @return sequence group to operate on | |
2298 | */ | |
2299 | 12 | SequenceGroup getGroup() |
2300 | { | |
2301 | 12 | SequenceGroup sg = ap.av.getSelectionGroup(); |
2302 | // this method won't add a new group if it already exists | |
2303 | 12 | if (sg != null) |
2304 | { | |
2305 | 12 | ap.av.getAlignment().addGroup(sg); |
2306 | } | |
2307 | ||
2308 | 12 | return sg; |
2309 | } | |
2310 | ||
2311 | /** | |
2312 | * Shows a dialog where the sequence name and description may be edited. If a | |
2313 | * name containing spaces is entered, these are converted to underscores, with | |
2314 | * a warning message. | |
2315 | */ | |
2316 | 0 | void sequenceName_actionPerformed() |
2317 | { | |
2318 | 0 | EditNameDialog dialog = new EditNameDialog(sequence.getName(), |
2319 | sequence.getDescription(), | |
2320 | MessageManager.getString("label.sequence_name"), | |
2321 | MessageManager.getString("label.sequence_description")); | |
2322 | 0 | dialog.showDialog(ap.alignFrame, MessageManager |
2323 | .getString("label.edit_sequence_name_description"), () -> { | |
2324 | 0 | if (dialog.getName() != null) |
2325 | { | |
2326 | 0 | if (dialog.getName().indexOf(" ") > -1) |
2327 | { | |
2328 | 0 | String ok = MessageManager.getString("action.ok"); |
2329 | 0 | String cancel = MessageManager.getString("action.cancel"); |
2330 | 0 | String message = MessageManager.getString( |
2331 | "label.spaces_converted_to_underscores"); | |
2332 | 0 | String title = MessageManager.getString( |
2333 | "label.no_spaces_allowed_sequence_name"); | |
2334 | 0 | Object[] options = new Object[] { ok, cancel }; |
2335 | ||
2336 | 0 | JvOptionPane.frameDialog(message, title, |
2337 | JvOptionPane.WARNING_MESSAGE, null, null, null, | |
2338 | false); | |
2339 | } | |
2340 | 0 | sequence.setName(dialog.getName().replace(' ', '_')); |
2341 | 0 | ap.paintAlignment(false, false); |
2342 | } | |
2343 | 0 | sequence.setDescription(dialog.getDescription()); |
2344 | 0 | ap.av.firePropertyChange("alignment", null, |
2345 | ap.av.getAlignment().getSequences()); | |
2346 | }); | |
2347 | } | |
2348 | ||
2349 | /** | |
2350 | * DOCUMENT ME! | |
2351 | * | |
2352 | * @param e | |
2353 | * DOCUMENT ME! | |
2354 | */ | |
2355 | 0 | void unGroupMenuItem_actionPerformed() |
2356 | { | |
2357 | 0 | SequenceGroup sg = ap.av.getSelectionGroup(); |
2358 | 0 | ap.av.getAlignment().deleteGroup(sg); |
2359 | 0 | ap.av.setSelectionGroup(null); |
2360 | 0 | refresh(); |
2361 | } | |
2362 | ||
2363 | 0 | void createGroupMenuItem_actionPerformed() |
2364 | { | |
2365 | 0 | getGroup(); // implicitly creates group - note - should apply defaults / use |
2366 | // standard alignment window logic for this | |
2367 | 0 | refresh(); |
2368 | } | |
2369 | ||
2370 | /** | |
2371 | * Offers a colour chooser and sets the selected colour as the group outline | |
2372 | */ | |
2373 | 0 | protected void outline_actionPerformed() |
2374 | { | |
2375 | 0 | String title = MessageManager.getString("label.select_outline_colour"); |
2376 | 0 | ColourChooserListener listener = new ColourChooserListener() |
2377 | { | |
2378 | 0 | @Override |
2379 | public void colourSelected(Color c) | |
2380 | { | |
2381 | 0 | getGroup().setOutlineColour(c); |
2382 | 0 | refresh(); |
2383 | } | |
2384 | }; | |
2385 | 0 | JalviewColourChooser.showColourChooser(Desktop.getDesktop(), title, |
2386 | Color.BLUE, listener); | |
2387 | } | |
2388 | ||
2389 | /** | |
2390 | * DOCUMENT ME! | |
2391 | * | |
2392 | * @param e | |
2393 | * DOCUMENT ME! | |
2394 | */ | |
2395 | 0 | public void showBoxes_actionPerformed() |
2396 | { | |
2397 | 0 | getGroup().setDisplayBoxes(showBoxes.isSelected()); |
2398 | 0 | refresh(); |
2399 | } | |
2400 | ||
2401 | /** | |
2402 | * DOCUMENT ME! | |
2403 | * | |
2404 | * @param e | |
2405 | * DOCUMENT ME! | |
2406 | */ | |
2407 | 0 | public void showText_actionPerformed() |
2408 | { | |
2409 | 0 | getGroup().setDisplayText(showText.isSelected()); |
2410 | 0 | refresh(); |
2411 | } | |
2412 | ||
2413 | /** | |
2414 | * DOCUMENT ME! | |
2415 | * | |
2416 | * @param e | |
2417 | * DOCUMENT ME! | |
2418 | */ | |
2419 | 0 | public void showColourText_actionPerformed() |
2420 | { | |
2421 | 0 | getGroup().setColourText(showColourText.isSelected()); |
2422 | 0 | refresh(); |
2423 | } | |
2424 | ||
2425 | 0 | void hideSequences(boolean representGroup) |
2426 | { | |
2427 | 0 | ap.av.hideSequences(sequence, representGroup); |
2428 | } | |
2429 | ||
2430 | 0 | public void copy_actionPerformed() |
2431 | { | |
2432 | 0 | ap.alignFrame.copy_actionPerformed(); |
2433 | } | |
2434 | ||
2435 | 0 | public void cut_actionPerformed() |
2436 | { | |
2437 | 0 | ap.alignFrame.cut_actionPerformed(); |
2438 | } | |
2439 | ||
2440 | 0 | void changeCase(ActionEvent e) |
2441 | { | |
2442 | 0 | Object source = e.getSource(); |
2443 | 0 | SequenceGroup sg = ap.av.getSelectionGroup(); |
2444 | ||
2445 | 0 | if (sg != null) |
2446 | { | |
2447 | 0 | List<int[]> startEnd = ap.av.getVisibleRegionBoundaries( |
2448 | sg.getStartRes(), sg.getEndRes() + 1); | |
2449 | ||
2450 | 0 | String description; |
2451 | 0 | int caseChange; |
2452 | ||
2453 | 0 | if (source == toggle) |
2454 | { | |
2455 | 0 | description = MessageManager.getString("label.toggle_case"); |
2456 | 0 | caseChange = ChangeCaseCommand.TOGGLE_CASE; |
2457 | } | |
2458 | 0 | else if (source == upperCase) |
2459 | { | |
2460 | 0 | description = MessageManager.getString("label.to_upper_case"); |
2461 | 0 | caseChange = ChangeCaseCommand.TO_UPPER; |
2462 | } | |
2463 | else | |
2464 | { | |
2465 | 0 | description = MessageManager.getString("label.to_lower_case"); |
2466 | 0 | caseChange = ChangeCaseCommand.TO_LOWER; |
2467 | } | |
2468 | ||
2469 | 0 | ChangeCaseCommand caseCommand = new ChangeCaseCommand(description, |
2470 | sg.getSequencesAsArray(ap.av.getHiddenRepSequences()), | |
2471 | startEnd, caseChange); | |
2472 | ||
2473 | 0 | ap.alignFrame.addHistoryItem(caseCommand); |
2474 | ||
2475 | 0 | ap.av.firePropertyChange("alignment", null, |
2476 | ap.av.getAlignment().getSequences()); | |
2477 | ||
2478 | } | |
2479 | } | |
2480 | ||
2481 | 0 | public void outputText_actionPerformed(ActionEvent e) |
2482 | { | |
2483 | 0 | CutAndPasteTransfer cap = new CutAndPasteTransfer(); |
2484 | 0 | cap.setForInput(null); |
2485 | 0 | Desktop.addInternalFrame(cap, MessageManager |
2486 | .formatMessage("label.alignment_output_command", new Object[] | |
2487 | { e.getActionCommand() }), 600, 500); | |
2488 | ||
2489 | 0 | String[] omitHidden = null; |
2490 | ||
2491 | 0 | jalview.bin.Console.outPrintln("PROMPT USER HERE"); // TODO: decide if a |
2492 | // prompt happens | |
2493 | // or we simply trust the user wants | |
2494 | // wysiwig behaviour | |
2495 | ||
2496 | 0 | FileFormatI fileFormat = FileFormats.getInstance() |
2497 | .forName(e.getActionCommand()); | |
2498 | 0 | cap.setText( |
2499 | new FormatAdapter(ap).formatSequences(fileFormat, ap, true)); | |
2500 | } | |
2501 | ||
2502 | 0 | public void sequenceFeature_actionPerformed() |
2503 | { | |
2504 | 0 | SequenceGroup sg = ap.av.getSelectionGroup(); |
2505 | 0 | if (sg == null) |
2506 | { | |
2507 | 0 | return; |
2508 | } | |
2509 | ||
2510 | 0 | List<SequenceI> seqs = new ArrayList<>(); |
2511 | 0 | List<SequenceFeature> features = new ArrayList<>(); |
2512 | ||
2513 | /* | |
2514 | * assemble dataset sequences, and template new sequence features, | |
2515 | * for the amend features dialog | |
2516 | */ | |
2517 | 0 | int gSize = sg.getSize(); |
2518 | 0 | for (int i = 0; i < gSize; i++) |
2519 | { | |
2520 | 0 | int start = sg.getSequenceAt(i).findPosition(sg.getStartRes()); |
2521 | 0 | int end = sg.findEndRes(sg.getSequenceAt(i)); |
2522 | 0 | if (start <= end) |
2523 | { | |
2524 | 0 | seqs.add(sg.getSequenceAt(i).getDatasetSequence()); |
2525 | 0 | features.add(new SequenceFeature(null, null, start, end, null)); |
2526 | } | |
2527 | } | |
2528 | ||
2529 | /* | |
2530 | * an entirely gapped region will generate empty lists of sequence / features | |
2531 | */ | |
2532 | 0 | if (!seqs.isEmpty()) |
2533 | { | |
2534 | 0 | new FeatureEditor(ap, seqs, features, true).showDialog(); |
2535 | } | |
2536 | } | |
2537 | ||
2538 | 0 | public void textColour_actionPerformed() |
2539 | { | |
2540 | 0 | SequenceGroup sg = getGroup(); |
2541 | 0 | if (sg != null) |
2542 | { | |
2543 | 0 | new TextColourChooser().chooseColour(ap, sg); |
2544 | } | |
2545 | } | |
2546 | ||
2547 | /** | |
2548 | * Shows a dialog where sequence characters may be edited. Any changes are | |
2549 | * applied, and added as an available 'Undo' item in the edit commands | |
2550 | * history. | |
2551 | */ | |
2552 | 0 | public void editSequence_actionPerformed() |
2553 | { | |
2554 | 0 | SequenceGroup sg = ap.av.getSelectionGroup(); |
2555 | ||
2556 | 0 | SequenceI seq = sequence; |
2557 | 0 | if (sg != null) |
2558 | { | |
2559 | 0 | if (seq == null) |
2560 | { | |
2561 | 0 | seq = sg.getSequenceAt(0); |
2562 | } | |
2563 | ||
2564 | 0 | EditNameDialog dialog = new EditNameDialog( |
2565 | seq.getSequenceAsString(sg.getStartRes(), sg.getEndRes() + 1), | |
2566 | null, MessageManager.getString("label.edit_sequence"), null); | |
2567 | 0 | dialog.showDialog(ap.alignFrame, |
2568 | MessageManager.getString("label.edit_sequence"), () -> { | |
2569 | 0 | EditCommand editCommand = new EditCommand( |
2570 | MessageManager.getString("label.edit_sequences"), | |
2571 | Action.REPLACE, | |
2572 | dialog.getName().replace(' ', | |
2573 | ap.av.getGapCharacter()), | |
2574 | sg.getSequencesAsArray( | |
2575 | ap.av.getHiddenRepSequences()), | |
2576 | sg.getStartRes(), sg.getEndRes() + 1, | |
2577 | ap.av.getAlignment()); | |
2578 | 0 | ap.alignFrame.addHistoryItem(editCommand); |
2579 | 0 | ap.av.firePropertyChange("alignment", null, |
2580 | ap.av.getAlignment().getSequences()); | |
2581 | }); | |
2582 | } | |
2583 | } | |
2584 | ||
2585 | /** | |
2586 | * Action on user selecting an item from the colour menu (that does not have | |
2587 | * its bespoke action handler) | |
2588 | * | |
2589 | * @return | |
2590 | */ | |
2591 | 3 | @Override |
2592 | public void changeColour_actionPerformed(String colourSchemeName) | |
2593 | { | |
2594 | 3 | SequenceGroup sg = getGroup(); |
2595 | /* | |
2596 | * switch to the chosen colour scheme (or null for None) | |
2597 | */ | |
2598 | 3 | ColourSchemeI colourScheme = ColourSchemes.getInstance() |
2599 | .getColourScheme(colourSchemeName, ap.av, sg, | |
2600 | ap.av.getHiddenRepSequences()); | |
2601 | 3 | sg.setColourScheme(colourScheme); |
2602 | 3 | if (colourScheme instanceof Blosum62ColourScheme |
2603 | || colourScheme instanceof PIDColourScheme) | |
2604 | { | |
2605 | 0 | sg.cs.setConsensus(AAFrequency.calculate( |
2606 | sg.getSequences(ap.av.getHiddenRepSequences()), | |
2607 | sg.getStartRes(), sg.getEndRes() + 1)); | |
2608 | } | |
2609 | ||
2610 | 3 | refresh(); |
2611 | } | |
2612 | ||
2613 | } |