Clover icon

Coverage Report

  1. Project Clover database Thu Aug 13 2020 12:04:21 BST
  2. Package jalview.gui

File StructureViewerBase.java

 

Coverage histogram

../../img/srcFileCovDistChart6.png
33% of files have more coverage

Code metrics

132
340
67
2
1,245
905
159
0.47
5.07
33.5
2.37

Classes

Class Line # Actions
StructureViewerBase 75 340 159
0.5139146451.4%
StructureViewerBase.ViewerColour 81 0 0
-1.0 -
 

Contributing tests

This file is covered by 11 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.gui;
22   
23    import java.awt.Color;
24    import java.awt.Component;
25    import java.awt.event.ActionEvent;
26    import java.awt.event.ActionListener;
27    import java.awt.event.ItemEvent;
28    import java.awt.event.ItemListener;
29    import java.io.BufferedReader;
30    import java.io.File;
31    import java.io.FileOutputStream;
32    import java.io.FileReader;
33    import java.io.IOException;
34    import java.io.PrintWriter;
35    import java.util.ArrayList;
36    import java.util.List;
37    import java.util.Random;
38    import java.util.Vector;
39   
40    import javax.swing.ButtonGroup;
41    import javax.swing.JCheckBoxMenuItem;
42    import javax.swing.JMenu;
43    import javax.swing.JMenuItem;
44    import javax.swing.JRadioButtonMenuItem;
45    import javax.swing.event.MenuEvent;
46    import javax.swing.event.MenuListener;
47   
48    import jalview.api.AlignmentViewPanel;
49    import jalview.bin.Cache;
50    import jalview.datamodel.AlignmentI;
51    import jalview.datamodel.PDBEntry;
52    import jalview.datamodel.SequenceI;
53    import jalview.gui.JalviewColourChooser.ColourChooserListener;
54    import jalview.gui.StructureViewer.ViewerType;
55    import jalview.gui.ViewSelectionMenu.ViewSetProvider;
56    import jalview.io.DataSourceType;
57    import jalview.io.JalviewFileChooser;
58    import jalview.io.JalviewFileView;
59    import jalview.jbgui.GStructureViewer;
60    import jalview.schemes.ColourSchemeI;
61    import jalview.schemes.ColourSchemes;
62    import jalview.structure.StructureMapping;
63    import jalview.structures.models.AAStructureBindingModel;
64    import jalview.util.BrowserLauncher;
65    import jalview.util.MessageManager;
66    import jalview.ws.dbsources.Pdb;
67   
68    /**
69    * Base class with common functionality for JMol, Chimera or other structure
70    * viewers.
71    *
72    * @author gmcarstairs
73    *
74    */
 
75    public abstract class StructureViewerBase extends GStructureViewer
76    implements Runnable, ViewSetProvider
77    {
78    /*
79    * names for colour options (additional to Jalview colour schemes)
80    */
 
81    enum ViewerColour
82    {
83    BySequence, ByChain, ChargeCysteine, ByViewer
84    }
85   
86    /**
87    * list of sequenceSet ids associated with the view
88    */
89    protected List<String> _aps = new ArrayList<>();
90   
91    /**
92    * list of alignment panels to use for superposition
93    */
94    protected Vector<AlignmentViewPanel> _alignwith = new Vector<>();
95   
96    /**
97    * list of alignment panels that are used for colouring structures by aligned
98    * sequences
99    */
100    protected Vector<AlignmentViewPanel> _colourwith = new Vector<>();
101   
102    private String viewId = null;
103   
104    private AlignmentPanel ap;
105   
106    protected boolean alignAddedStructures = false;
107   
108    protected volatile boolean _started = false;
109   
110    protected volatile boolean addingStructures = false;
111   
112    protected Thread worker = null;
113   
114    protected boolean allChainsSelected = false;
115   
116    protected JMenu viewSelectionMenu;
117   
118    /**
119    * set after sequence colouring has been applied for this structure viewer.
120    * used to determine if the final sequence/structure mapping has been
121    * determined
122    */
123    protected volatile boolean seqColoursApplied = false;
124   
125    private IProgressIndicator progressBar = null;
126   
127    private Random random = new Random();
128   
129    /**
130    * Default constructor
131    */
 
132  7 toggle public StructureViewerBase()
133    {
134  7 super();
135    }
136   
137    /**
138    * @return true if added structures should be aligned to existing one(s)
139    */
 
140  0 toggle @Override
141    public boolean isAlignAddedStructures()
142    {
143  0 return alignAddedStructures;
144    }
145   
146    /**
147    *
148    * @param true
149    * if added structures should be aligned to existing one(s)
150    */
 
151  1 toggle @Override
152    public void setAlignAddedStructures(boolean alignAdded)
153    {
154  1 alignAddedStructures = alignAdded;
155    }
156   
157    /**
158    *
159    * @param ap2
160    * @return true if this Jmol instance is linked with the given alignPanel
161    */
 
162  0 toggle public boolean isLinkedWith(AlignmentPanel ap2)
163    {
164  0 return _aps.contains(ap2.av.getSequenceSetId());
165    }
166   
 
167  20 toggle public boolean isUsedforaligment(AlignmentViewPanel ap2)
168    {
169   
170  20 return (_alignwith != null) && _alignwith.contains(ap2);
171    }
172   
 
173  423 toggle @Override
174    public boolean isUsedForColourBy(AlignmentViewPanel ap2)
175    {
176  423 return (_colourwith != null) && _colourwith.contains(ap2);
177    }
178   
179    /**
180    *
181    * @return TRUE if the view is NOT being coloured by the alignment colours.
182    */
 
183  20 toggle public boolean isColouredByViewer()
184    {
185  20 return !getBinding().isColourBySequence();
186    }
187   
 
188  103 toggle public String getViewId()
189    {
190  103 if (viewId == null)
191    {
192  0 viewId = System.currentTimeMillis() + "." + this.hashCode();
193    }
194  103 return viewId;
195    }
196   
 
197  5 toggle protected void setViewId(String viewId)
198    {
199  5 this.viewId = viewId;
200    }
201   
 
202  34 toggle protected void buildActionMenu()
203    {
204  34 if (_alignwith == null)
205    {
206  0 _alignwith = new Vector<>();
207    }
208  34 if (_alignwith.size() == 0 && ap != null)
209    {
210  2 _alignwith.add(ap);
211    }
212  34 ;
213  34 for (Component c : viewerActionMenu.getMenuComponents())
214    {
215  37 if (c != alignStructs)
216    {
217  3 viewerActionMenu.remove((JMenuItem) c);
218    }
219    }
220    }
221   
 
222  139 toggle @Override
223    public AlignmentPanel getAlignmentPanel()
224    {
225  139 return ap;
226    }
227   
 
228  15 toggle protected void setAlignmentPanel(AlignmentPanel alp)
229    {
230  15 this.ap = alp;
231    }
232   
 
233  1 toggle @Override
234    public AlignmentPanel[] getAllAlignmentPanels()
235    {
236  1 AlignmentPanel[] t, list = new AlignmentPanel[0];
237  1 for (String setid : _aps)
238    {
239  1 AlignmentPanel[] panels = PaintRefresher.getAssociatedPanels(setid);
240  1 if (panels != null)
241    {
242  1 t = new AlignmentPanel[list.length + panels.length];
243  1 System.arraycopy(list, 0, t, 0, list.length);
244  1 System.arraycopy(panels, 0, t, list.length, panels.length);
245  1 list = t;
246    }
247    }
248   
249  1 return list;
250    }
251   
252    /**
253    * set the primary alignmentPanel reference and add another alignPanel to the
254    * list of ones to use for colouring and aligning
255    *
256    * @param nap
257    */
 
258  53 toggle public void addAlignmentPanel(AlignmentPanel nap)
259    {
260  53 if (getAlignmentPanel() == null)
261    {
262  7 setAlignmentPanel(nap);
263    }
264  53 if (!_aps.contains(nap.av.getSequenceSetId()))
265    {
266  10 _aps.add(nap.av.getSequenceSetId());
267    }
268    }
269   
270    /**
271    * remove any references held to the given alignment panel
272    *
273    * @param nap
274    */
 
275  36 toggle @Override
276    public void removeAlignmentPanel(AlignmentViewPanel nap)
277    {
278  36 try
279    {
280  36 _alignwith.remove(nap);
281  36 _colourwith.remove(nap);
282  36 if (getAlignmentPanel() == nap)
283    {
284  1 setAlignmentPanel(null);
285  1 for (AlignmentPanel aps : getAllAlignmentPanels())
286    {
287  0 if (aps != nap)
288    {
289  0 setAlignmentPanel(aps);
290  0 break;
291    }
292    }
293    }
294    } catch (Exception ex)
295    {
296    }
297  36 if (getAlignmentPanel() != null)
298    {
299  34 buildActionMenu();
300    }
301    }
302   
 
303  1 toggle public void useAlignmentPanelForSuperposition(AlignmentPanel nap)
304    {
305  1 addAlignmentPanel(nap);
306  1 if (!_alignwith.contains(nap))
307    {
308  1 _alignwith.add(nap);
309    }
310    }
311   
 
312  35 toggle public void excludeAlignmentPanelForSuperposition(AlignmentPanel nap)
313    {
314  35 if (_alignwith.contains(nap))
315    {
316  0 _alignwith.remove(nap);
317    }
318    }
319   
 
320  8 toggle public void useAlignmentPanelForColourbyseq(AlignmentPanel nap,
321    boolean enableColourBySeq)
322    {
323  8 useAlignmentPanelForColourbyseq(nap);
324  8 getBinding().setColourBySequence(enableColourBySeq);
325  8 seqColour.setSelected(enableColourBySeq);
326  8 viewerColour.setSelected(!enableColourBySeq);
327    }
328   
 
329  10 toggle public void useAlignmentPanelForColourbyseq(AlignmentPanel nap)
330    {
331  10 addAlignmentPanel(nap);
332  10 if (!_colourwith.contains(nap))
333    {
334  10 _colourwith.add(nap);
335    }
336    }
337   
 
338  27 toggle public void excludeAlignmentPanelForColourbyseq(AlignmentPanel nap)
339    {
340  27 if (_colourwith.contains(nap))
341    {
342  0 _colourwith.remove(nap);
343    }
344    }
345   
346    public abstract ViewerType getViewerType();
347   
348    /**
349    * add a new structure (with associated sequences and chains) to this viewer,
350    * retrieving it if necessary first.
351    *
352    * @param pdbentry
353    * @param seqs
354    * @param chains
355    * @param align
356    * if true, new structure(s) will be aligned using associated
357    * alignment
358    * @param alignFrame
359    */
 
360  1 toggle protected void addStructure(final PDBEntry pdbentry,
361    final SequenceI[] seqs, final String[] chains,
362    final IProgressIndicator alignFrame)
363    {
364  1 if (pdbentry.getFile() == null)
365    {
366  0 if (worker != null && worker.isAlive())
367    {
368    // a retrieval is in progress, wait around and add ourselves to the
369    // queue.
370  0 new Thread(new Runnable()
371    {
 
372  0 toggle @Override
373    public void run()
374    {
375  0 while (worker != null && worker.isAlive() && _started)
376    {
377  0 try
378    {
379  0 Thread.sleep(100 + ((int) Math.random() * 100));
380   
381    } catch (Exception e)
382    {
383    }
384    }
385    // and call ourselves again.
386  0 addStructure(pdbentry, seqs, chains, alignFrame);
387    }
388    }).start();
389  0 return;
390    }
391    }
392    // otherwise, start adding the structure.
393  1 getBinding().addSequenceAndChain(new PDBEntry[] { pdbentry },
394    new SequenceI[][]
395    { seqs }, new String[][] { chains });
396  1 addingStructures = true;
397  1 _started = false;
398  1 worker = new Thread(this);
399  1 worker.start();
400  1 return;
401    }
402   
 
403  1 toggle protected boolean hasPdbId(String pdbId)
404    {
405  1 return getBinding().hasPdbId(pdbId);
406    }
407   
408    /**
409    * Returns a list of any viewer of the instantiated type. The list is
410    * restricted to those linked to the given alignment panel if it is not null.
411    */
 
412  0 toggle protected List<StructureViewerBase> getViewersFor(AlignmentPanel alp)
413    {
414  0 return Desktop.instance.getStructureViewers(alp, this.getClass());
415    }
416   
 
417  1 toggle @Override
418    public void addToExistingViewer(PDBEntry pdbentry, SequenceI[] seq,
419    String[] chains, final AlignmentViewPanel apanel, String pdbId)
420    {
421    /*
422    * JAL-1742 exclude view with this structure already mapped (don't offer
423    * to align chain B to chain A of the same structure); code may defend
424    * against this possibility before we reach here
425    */
426  1 if (hasPdbId(pdbId))
427    {
428  0 return;
429    }
430  1 AlignmentPanel alignPanel = (AlignmentPanel) apanel; // Implementation error if this
431    // cast fails
432  1 useAlignmentPanelForSuperposition(alignPanel);
433  1 addStructure(pdbentry, seq, chains, alignPanel.alignFrame);
434    }
435   
436    /**
437    * Adds mappings for the given sequences to an already opened PDB structure,
438    * and updates any viewers that have the PDB file
439    *
440    * @param seq
441    * @param chains
442    * @param apanel
443    * @param pdbFilename
444    */
 
445  0 toggle public void addSequenceMappingsToStructure(SequenceI[] seq,
446    String[] chains, final AlignmentViewPanel alpanel,
447    String pdbFilename)
448    {
449  0 AlignmentPanel apanel = (AlignmentPanel) alpanel;
450   
451    // TODO : Fix multiple seq to one chain issue here.
452    /*
453    * create the mappings
454    */
455  0 apanel.getStructureSelectionManager().setMapping(seq, chains,
456    pdbFilename, DataSourceType.FILE, getProgressIndicator());
457   
458    /*
459    * alert the FeatureRenderer to show new (PDB RESNUM) features
460    */
461  0 if (apanel.getSeqPanel().seqCanvas.fr != null)
462    {
463  0 apanel.getSeqPanel().seqCanvas.fr.featuresAdded();
464    // note - we don't do a refresh for structure here because we do it
465    // explicitly for all panels later on
466  0 apanel.paintAlignment(true, false);
467    }
468   
469    /*
470    * add the sequences to any other viewers (of the same type) for this pdb
471    * file
472    */
473    // JBPNOTE: this looks like a binding routine, rather than a gui routine
474  0 for (StructureViewerBase viewer : getViewersFor(null))
475    {
476  0 AAStructureBindingModel bindingModel = viewer.getBinding();
477  0 for (int pe = 0; pe < bindingModel.getPdbCount(); pe++)
478    {
479  0 if (bindingModel.getPdbEntry(pe).getFile().equals(pdbFilename))
480    {
481  0 bindingModel.addSequence(pe, seq);
482  0 viewer.addAlignmentPanel(apanel);
483    /*
484    * add it to the set of alignments used for colouring structure by
485    * sequence
486    */
487  0 viewer.useAlignmentPanelForColourbyseq(apanel);
488  0 viewer.buildActionMenu();
489  0 apanel.getStructureSelectionManager()
490    .sequenceColoursChanged(apanel);
491  0 break;
492    }
493    }
494    }
495    }
496   
 
497  1 toggle @Override
498    public boolean addAlreadyLoadedFile(SequenceI[] seq, String[] chains,
499    final AlignmentViewPanel apanel, String pdbId)
500    {
501  1 String alreadyMapped = apanel.getStructureSelectionManager()
502    .alreadyMappedToFile(pdbId);
503   
504  1 if (alreadyMapped == null)
505    {
506  1 return false;
507    }
508   
509  0 addSequenceMappingsToStructure(seq, chains, apanel, alreadyMapped);
510  0 return true;
511    }
512   
 
513  7 toggle void setChainMenuItems(List<String> chainNames)
514    {
515  7 chainMenu.removeAll();
516  7 if (chainNames == null || chainNames.isEmpty())
517    {
518  0 return;
519    }
520  7 JMenuItem menuItem = new JMenuItem(
521    MessageManager.getString("label.all"));
522  7 menuItem.addActionListener(new ActionListener()
523    {
 
524  0 toggle @Override
525    public void actionPerformed(ActionEvent evt)
526    {
527  0 allChainsSelected = true;
528  0 for (int i = 0; i < chainMenu.getItemCount(); i++)
529    {
530  0 if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
531    {
532  0 ((JCheckBoxMenuItem) chainMenu.getItem(i)).setSelected(true);
533    }
534    }
535  0 showSelectedChains();
536  0 allChainsSelected = false;
537    }
538    });
539   
540  7 chainMenu.add(menuItem);
541   
542  7 for (String chain : chainNames)
543    {
544  22 menuItem = new JCheckBoxMenuItem(chain, true);
545  22 menuItem.addItemListener(new ItemListener()
546    {
 
547  0 toggle @Override
548    public void itemStateChanged(ItemEvent evt)
549    {
550  0 if (!allChainsSelected)
551    {
552  0 showSelectedChains();
553    }
554    }
555    });
556   
557  22 chainMenu.add(menuItem);
558    }
559    }
560   
561    /**
562    * Action on selecting one of Jalview's registered colour schemes
563    */
 
564  0 toggle @Override
565    public void changeColour_actionPerformed(String colourSchemeName)
566    {
567  0 AlignmentI al = getAlignmentPanel().av.getAlignment();
568  0 ColourSchemeI cs = ColourSchemes.getInstance()
569    .getColourScheme(colourSchemeName, getAlignmentPanel().av, al,
570    null);
571  0 getBinding().colourByJalviewColourScheme(cs);
572    }
573   
574    /**
575    * Builds the colour menu
576    */
 
577  7 toggle protected void buildColourMenu()
578    {
579  7 colourMenu.removeAll();
580  7 AlignmentI al = getAlignmentPanel().av.getAlignment();
581   
582    /*
583    * add colour by sequence, by chain, by charge and cysteine
584    */
585  7 colourMenu.add(seqColour);
586  7 colourMenu.add(chainColour);
587  7 colourMenu.add(chargeColour);
588  7 chargeColour.setEnabled(!al.isNucleotide());
589   
590    /*
591    * add all 'simple' (per-residue) colour schemes registered to Jalview
592    */
593  7 ButtonGroup itemGroup = ColourMenuHelper.addMenuItems(colourMenu, this,
594    al, true);
595   
596    /*
597    * add 'colour by viewer' (menu item text is set in subclasses)
598    */
599  7 viewerColour.setSelected(false);
600  7 viewerColour.addActionListener(new ActionListener()
601    {
 
602  0 toggle @Override
603    public void actionPerformed(ActionEvent actionEvent)
604    {
605  0 viewerColour_actionPerformed();
606    }
607    });
608  7 colourMenu.add(viewerColour);
609   
610    /*
611    * add 'set background colour'
612    */
613  7 JMenuItem backGround = new JMenuItem();
614  7 backGround
615    .setText(MessageManager.getString("action.background_colour"));
616  7 backGround.addActionListener(new ActionListener()
617    {
 
618  0 toggle @Override
619    public void actionPerformed(ActionEvent actionEvent)
620    {
621  0 background_actionPerformed();
622    }
623    });
624  7 colourMenu.add(backGround);
625   
626    /*
627    * add colour buttons to a group so their selection is
628    * mutually exclusive (background colour is a separate option)
629    */
630  7 itemGroup.add(seqColour);
631  7 itemGroup.add(chainColour);
632  7 itemGroup.add(chargeColour);
633  7 itemGroup.add(viewerColour);
634    }
635   
636    /**
637    * Construct menu items
638    */
 
639  7 toggle protected void initMenus()
640    {
641  7 AAStructureBindingModel binding = getBinding();
642   
643  7 seqColour = new JRadioButtonMenuItem();
644  7 seqColour.setText(MessageManager.getString("action.by_sequence"));
645  7 seqColour.setName(ViewerColour.BySequence.name());
646  7 seqColour.setSelected(binding.isColourBySequence());
647  7 seqColour.addActionListener(new ActionListener()
648    {
 
649  0 toggle @Override
650    public void actionPerformed(ActionEvent actionEvent)
651    {
652  0 seqColour_actionPerformed();
653    }
654    });
655   
656  7 chainColour = new JRadioButtonMenuItem();
657  7 chainColour.setText(MessageManager.getString("action.by_chain"));
658  7 chainColour.setName(ViewerColour.ByChain.name());
659  7 chainColour.addActionListener(new ActionListener()
660    {
 
661  0 toggle @Override
662    public void actionPerformed(ActionEvent actionEvent)
663    {
664  0 chainColour_actionPerformed();
665    }
666    });
667   
668  7 chargeColour = new JRadioButtonMenuItem();
669  7 chargeColour.setText(MessageManager.getString("label.charge_cysteine"));
670  7 chargeColour.setName(ViewerColour.ChargeCysteine.name());
671  7 chargeColour.addActionListener(new ActionListener()
672    {
 
673  0 toggle @Override
674    public void actionPerformed(ActionEvent actionEvent)
675    {
676  0 chargeColour_actionPerformed();
677    }
678    });
679   
680  7 viewerColour = new JRadioButtonMenuItem();
681  7 viewerColour
682    .setText(MessageManager.getString("label.colour_with_viewer"));
683  7 viewerColour.setToolTipText(MessageManager
684    .getString("label.let_viewer_manage_structure_colours"));
685  7 viewerColour.setName(ViewerColour.ByViewer.name());
686  7 viewerColour.setSelected(!binding.isColourBySequence());
687   
688  7 if (_colourwith == null)
689    {
690  0 _colourwith = new Vector<>();
691    }
692  7 if (_alignwith == null)
693    {
694  0 _alignwith = new Vector<>();
695    }
696   
697  7 ViewSelectionMenu seqColourBy = new ViewSelectionMenu(
698    MessageManager.getString("label.colour_by"), this, _colourwith,
699    new ItemListener()
700    {
 
701  0 toggle @Override
702    public void itemStateChanged(ItemEvent e)
703    {
704  0 if (!seqColour.isSelected())
705    {
706  0 seqColour.doClick();
707    }
708    else
709    {
710    // update the viewer display now.
711  0 seqColour_actionPerformed();
712    }
713    }
714    });
715  7 viewMenu.add(seqColourBy);
716   
717  7 final ItemListener handler = new ItemListener()
718    {
 
719  7 toggle @Override
720    public void itemStateChanged(ItemEvent e)
721    {
722  7 if (_alignwith.isEmpty())
723    {
724  7 alignStructs.setEnabled(false);
725  7 alignStructs.setToolTipText(null);
726    }
727    else
728    {
729  0 alignStructs.setEnabled(true);
730  0 alignStructs.setToolTipText(MessageManager.formatMessage(
731    "label.align_structures_using_linked_alignment_views",
732    _alignwith.size()));
733    }
734    }
735    };
736  7 viewSelectionMenu = new ViewSelectionMenu(
737    MessageManager.getString("label.superpose_with"), this,
738    _alignwith, handler);
739  7 handler.itemStateChanged(null);
740  7 viewerActionMenu.add(viewSelectionMenu, 0);
741  7 viewerActionMenu.addMenuListener(new MenuListener()
742    {
 
743  0 toggle @Override
744    public void menuSelected(MenuEvent e)
745    {
746  0 handler.itemStateChanged(null);
747    }
748   
 
749  0 toggle @Override
750    public void menuDeselected(MenuEvent e)
751    {
752    }
753   
 
754  0 toggle @Override
755    public void menuCanceled(MenuEvent e)
756    {
757    }
758    });
759   
760  7 viewerActionMenu.setText(getViewerName());
761  7 helpItem.setText(MessageManager.formatMessage("label.viewer_help",
762    getViewerName()));
763   
764  7 buildColourMenu();
765    }
766   
767    /**
768    * Sends commands to the structure viewer to superimpose structures based on
769    * currently associated alignments. May optionally return an error message for
770    * the operation.
771    */
 
772  1 toggle @Override
773    protected String alignStructsWithAllAlignPanels()
774    {
775  1 if (getAlignmentPanel() == null)
776    {
777  0 return null;
778    }
779   
780  1 if (_alignwith.size() == 0)
781    {
782  0 _alignwith.add(getAlignmentPanel());
783    }
784   
785  1 String reply = null;
786  1 try
787    {
788  1 reply = getBinding().superposeStructures(_alignwith);
789  0 if (reply != null && !reply.isEmpty())
790    {
791  0 String text = MessageManager
792    .formatMessage("error.superposition_failed", reply);
793  0 statusBar.setText(text);
794    }
795    } catch (Exception e)
796    {
797  1 StringBuffer sp = new StringBuffer();
798  1 for (AlignmentViewPanel alignPanel : _alignwith)
799    {
800  1 sp.append("'" + alignPanel.getViewName() + "' ");
801    }
802  1 Cache.log.info("Couldn't align structures with the " + sp.toString()
803    + "associated alignment panels.", e);
804    }
805  1 return reply;
806    }
807   
808    /**
809    * Opens a colour chooser dialog, and applies the chosen colour to the
810    * background of the structure viewer
811    */
 
812  0 toggle @Override
813    public void background_actionPerformed()
814    {
815  0 String ttl = MessageManager.getString("label.select_background_colour");
816  0 ColourChooserListener listener = new ColourChooserListener()
817    {
 
818  0 toggle @Override
819    public void colourSelected(Color c)
820    {
821  0 getBinding().setBackgroundColour(c);
822    }
823    };
824  0 JalviewColourChooser.showColourChooser(this, ttl, null, listener);
825    }
826   
 
827  0 toggle @Override
828    public void viewerColour_actionPerformed()
829    {
830  0 if (viewerColour.isSelected())
831    {
832    // disable automatic sequence colouring.
833  0 getBinding().setColourBySequence(false);
834    }
835    }
836   
 
837  0 toggle @Override
838    public void chainColour_actionPerformed()
839    {
840  0 chainColour.setSelected(true);
841  0 getBinding().colourByChain();
842    }
843   
 
844  0 toggle @Override
845    public void chargeColour_actionPerformed()
846    {
847  0 chargeColour.setSelected(true);
848  0 getBinding().colourByCharge();
849    }
850   
 
851  7 toggle @Override
852    public void seqColour_actionPerformed()
853    {
854  7 AAStructureBindingModel binding = getBinding();
855  7 binding.setColourBySequence(seqColour.isSelected());
856  7 if (_colourwith == null)
857    {
858  0 _colourwith = new Vector<>();
859    }
860  7 if (binding.isColourBySequence())
861    {
862  4 if (!binding.isLoadingFromArchive())
863    {
864  4 if (_colourwith.size() == 0 && getAlignmentPanel() != null)
865    {
866    // Make the currently displayed alignment panel the associated view
867  0 _colourwith.add(getAlignmentPanel().alignFrame.alignPanel);
868    }
869    }
870    // Set the colour using the current view for the associated alignframe
871  4 for (AlignmentViewPanel alignPanel : _colourwith)
872    {
873  4 binding.colourBySequence(alignPanel);
874    }
875  4 seqColoursApplied = true;
876    }
877    }
878   
 
879  0 toggle @Override
880    public void pdbFile_actionPerformed()
881    {
882    // TODO: JAL-3048 not needed for Jalview-JS - save PDB file
883  0 JalviewFileChooser chooser = new JalviewFileChooser(
884    Cache.getProperty("LAST_DIRECTORY"));
885   
886  0 chooser.setFileView(new JalviewFileView());
887  0 chooser.setDialogTitle(MessageManager.getString("label.save_pdb_file"));
888  0 chooser.setToolTipText(MessageManager.getString("action.save"));
889   
890  0 int value = chooser.showSaveDialog(this);
891   
892  0 if (value == JalviewFileChooser.APPROVE_OPTION)
893    {
894  0 BufferedReader in = null;
895  0 try
896    {
897    // TODO: cope with multiple PDB files in view
898  0 in = new BufferedReader(
899    new FileReader(getBinding().getStructureFiles()[0]));
900  0 File outFile = chooser.getSelectedFile();
901   
902  0 PrintWriter out = new PrintWriter(new FileOutputStream(outFile));
903  0 String data;
904  0 while ((data = in.readLine()) != null)
905    {
906  0 if (!(data.indexOf("<PRE>") > -1 || data.indexOf("</PRE>") > -1))
907    {
908  0 out.println(data);
909    }
910    }
911  0 out.close();
912    } catch (Exception ex)
913    {
914  0 ex.printStackTrace();
915    } finally
916    {
917  0 if (in != null)
918    {
919  0 try
920    {
921  0 in.close();
922    } catch (IOException e)
923    {
924    // ignore
925    }
926    }
927    }
928    }
929    }
930   
 
931  0 toggle @Override
932    public void viewMapping_actionPerformed()
933    {
934  0 CutAndPasteTransfer cap = new CutAndPasteTransfer();
935  0 try
936    {
937  0 cap.appendText(getBinding().printMappings());
938    } catch (OutOfMemoryError e)
939    {
940  0 new OOMWarning(
941    "composing sequence-structure alignments for display in text box.",
942    e);
943  0 cap.dispose();
944  0 return;
945    }
946  0 Desktop.addInternalFrame(cap,
947    MessageManager.getString("label.pdb_sequence_mapping"), 550,
948    600);
949    }
950   
951    protected abstract String getViewerName();
952   
953    /**
954    * Configures the title and menu items of the viewer panel.
955    */
 
956  7 toggle @Override
957    public void updateTitleAndMenus()
958    {
959  7 AAStructureBindingModel binding = getBinding();
960  7 if (binding.hasFileLoadingError())
961    {
962  0 repaint();
963  0 return;
964    }
965  7 setChainMenuItems(binding.getChainNames());
966   
967  7 this.setTitle(binding.getViewerTitle(getViewerName(), true));
968   
969    /*
970    * enable 'Superpose with' if more than one mapped structure
971    */
972  7 viewSelectionMenu.setEnabled(false);
973  7 if (getBinding().getMappedStructureCount() > 1
974    && getBinding().getSequence().length > 1)
975    {
976  1 viewSelectionMenu.setEnabled(true);
977    }
978   
979    /*
980    * Show action menu if it has any enabled items
981    */
982  7 viewerActionMenu.setVisible(false);
983  19 for (int i = 0; i < viewerActionMenu.getItemCount(); i++)
984    {
985  13 if (viewerActionMenu.getItem(i).isEnabled())
986    {
987  1 viewerActionMenu.setVisible(true);
988  1 break;
989    }
990    }
991   
992  7 if (!binding.isLoadingFromArchive())
993    {
994  7 seqColour_actionPerformed();
995    }
996    }
997   
 
998  0 toggle @Override
999    public String toString()
1000    {
1001  0 return getTitle();
1002    }
1003   
 
1004  3 toggle @Override
1005    public boolean hasMapping()
1006    {
1007  3 if (worker != null && (addingStructures || _started))
1008    {
1009  2 return false;
1010    }
1011  1 if (getBinding() == null)
1012    {
1013  0 if (_aps == null || _aps.size() == 0)
1014    {
1015    // viewer has been closed, but we did at some point run.
1016  0 return true;
1017    }
1018  0 return false;
1019    }
1020  1 String[] pdbids = getBinding().getStructureFiles();
1021  1 if (pdbids == null)
1022    {
1023  0 return false;
1024    }
1025  1 int p=0;
1026  1 for (String pdbid:pdbids) {
1027  2 StructureMapping sm[] = getBinding().getSsm().getMapping(pdbid);
1028  2 if (sm!=null && sm.length>0 && sm[0]!=null) {
1029  2 p++;
1030    }
1031    }
1032    // only return true if there is a mapping for every structure file we have loaded
1033  1 if (p == 0 || p != pdbids.length)
1034    {
1035  0 return false;
1036    }
1037    // and that coloring has been applied
1038  1 return seqColoursApplied;
1039    }
1040   
 
1041  1 toggle @Override
1042    public void raiseViewer()
1043    {
1044  1 toFront();
1045    }
1046   
 
1047  10 toggle @Override
1048    public long startProgressBar(String msg)
1049    {
1050    // TODO would rather have startProgress/stopProgress as the
1051    // IProgressIndicator interface
1052  10 long tm = random.nextLong();
1053  10 if (progressBar != null)
1054    {
1055  10 progressBar.setProgressBar(msg, tm);
1056    }
1057  10 return tm;
1058    }
1059   
 
1060  10 toggle @Override
1061    public void stopProgressBar(String msg, long handle)
1062    {
1063  10 if (progressBar != null)
1064    {
1065  10 progressBar.setProgressBar(msg, handle);
1066    }
1067    }
1068   
 
1069  0 toggle protected IProgressIndicator getProgressIndicator()
1070    {
1071  0 return progressBar;
1072    }
1073   
 
1074  4 toggle protected void setProgressIndicator(IProgressIndicator pi)
1075    {
1076  4 progressBar = pi;
1077    }
1078   
 
1079  0 toggle protected void setProgressMessage(String message, long id)
1080    {
1081  0 if (progressBar != null)
1082    {
1083  0 progressBar.setProgressBar(message, id);
1084    }
1085    }
1086   
 
1087  0 toggle @Override
1088    public void showConsole(boolean show)
1089    {
1090    // default does nothing
1091    }
1092   
1093    /**
1094    * Show only the selected chain(s) in the viewer
1095    */
 
1096  0 toggle protected void showSelectedChains()
1097    {
1098  0 List<String> toshow = new ArrayList<>();
1099  0 for (int i = 0; i < chainMenu.getItemCount(); i++)
1100    {
1101  0 if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
1102    {
1103  0 JCheckBoxMenuItem item = (JCheckBoxMenuItem) chainMenu.getItem(i);
1104  0 if (item.isSelected())
1105    {
1106  0 toshow.add(item.getText());
1107    }
1108    }
1109    }
1110  0 getBinding().showChains(toshow);
1111    }
1112   
1113    /**
1114    * Tries to fetch a PDB file and save to a temporary local file. Returns the
1115    * saved file path if successful, or null if not.
1116    *
1117    * @param processingEntry
1118    * @return
1119    */
 
1120  0 toggle protected String fetchPdbFile(PDBEntry processingEntry)
1121    {
1122  0 String filePath = null;
1123  0 Pdb pdbclient = new Pdb();
1124  0 AlignmentI pdbseq = null;
1125  0 String pdbid = processingEntry.getId();
1126  0 long handle = System.currentTimeMillis()
1127    + Thread.currentThread().hashCode();
1128   
1129    /*
1130    * Write 'fetching PDB' progress on AlignFrame as we are not yet visible
1131    */
1132  0 String msg = MessageManager.formatMessage("status.fetching_pdb",
1133    new Object[]
1134    { pdbid });
1135  0 getAlignmentPanel().alignFrame.setProgressBar(msg, handle);
1136    // long hdl = startProgressBar(MessageManager.formatMessage(
1137    // "status.fetching_pdb", new Object[]
1138    // { pdbid }));
1139  0 try
1140    {
1141  0 pdbseq = pdbclient.getSequenceRecords(pdbid);
1142    } catch (Exception e)
1143    {
1144  0 System.err.println(
1145    "Error retrieving PDB id " + pdbid + ": " + e.getMessage());
1146    } finally
1147    {
1148  0 msg = pdbid + " " + MessageManager.getString("label.state_completed");
1149  0 getAlignmentPanel().alignFrame.setProgressBar(msg, handle);
1150    // stopProgressBar(msg, hdl);
1151    }
1152    /*
1153    * If PDB data were saved and are not invalid (empty alignment), return the
1154    * file path.
1155    */
1156  0 if (pdbseq != null && pdbseq.getHeight() > 0)
1157    {
1158    // just use the file name from the first sequence's first PDBEntry
1159  0 filePath = new File(pdbseq.getSequenceAt(0).getAllPDBEntries()
1160    .elementAt(0).getFile()).getAbsolutePath();
1161  0 processingEntry.setFile(filePath);
1162    }
1163  0 return filePath;
1164    }
1165   
1166    /**
1167    * If supported, saves the state of the structure viewer to a temporary file
1168    * and returns the file, else returns null
1169    *
1170    * @return
1171    */
 
1172  2 toggle public File saveSession()
1173    {
1174    // TODO: a wait loop to ensure the file is written fully before returning?
1175  2 return getBinding() == null ? null : getBinding().saveSession();
1176    }
1177   
1178    /**
1179    * Close down this instance of Jalview's Chimera viewer, giving the user the
1180    * option to close the associated Chimera window (process). They may wish to
1181    * keep it open until they have had an opportunity to save any work.
1182    *
1183    * @param forceClose
1184    * if true, close any linked Chimera process; if false, prompt first
1185    */
 
1186  7 toggle @Override
1187    public void closeViewer(boolean forceClose)
1188    {
1189  7 AAStructureBindingModel binding = getBinding();
1190  7 if (binding != null && binding.isViewerRunning())
1191    {
1192  0 if (!forceClose)
1193    {
1194  0 String viewerName = getViewerName();
1195  0 String prompt = MessageManager
1196    .formatMessage("label.confirm_close_viewer", new Object[]
1197    { binding.getViewerTitle(viewerName, false), viewerName });
1198  0 prompt = JvSwingUtils.wrapTooltip(true, prompt);
1199  0 int confirm = JvOptionPane.showConfirmDialog(this, prompt,
1200    MessageManager.getString("label.close_viewer"),
1201    JvOptionPane.YES_NO_CANCEL_OPTION);
1202    /*
1203    * abort closure if user hits escape or Cancel
1204    */
1205  0 if (confirm == JvOptionPane.CANCEL_OPTION
1206    || confirm == JvOptionPane.CLOSED_OPTION)
1207    {
1208  0 return;
1209    }
1210  0 forceClose = confirm == JvOptionPane.YES_OPTION;
1211    }
1212    }
1213  7 if (binding != null)
1214    {
1215  7 binding.closeViewer(forceClose);
1216    }
1217  7 setAlignmentPanel(null);
1218  7 _aps.clear();
1219  7 _alignwith.clear();
1220  7 _colourwith.clear();
1221    // TODO: check for memory leaks where instance isn't finalised because jmb
1222    // holds a reference to the window
1223    // jmb = null;
1224  7 dispose();
1225    }
1226   
 
1227  0 toggle @Override
1228    public void showHelp_actionPerformed()
1229    {
1230  0 try
1231    {
1232  0 String url = getBinding().getHelpURL();
1233  0 if (url != null)
1234    {
1235  0 BrowserLauncher.openURL(url);
1236    }
1237    } catch (IOException ex)
1238    {
1239  0 System.err
1240    .println("Show " + getViewerName() + " failed with: "
1241    + ex.getMessage());
1242    }
1243    }
1244   
1245    }