Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package jalview.gui

File StructureViewerBase.java

 

Coverage histogram

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

Code metrics

104
287
58
2
1,051
765
130
0.45
4.95
29
2.24

Classes

Class Line # Actions
StructureViewerBase 74 287 130 195
0.5657015456.6%
StructureViewerBase.ViewerColour 80 0 0 0
-1.0 -
 

Contributing tests

This file is covered by 17 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 jalview.api.AlignmentViewPanel;
24    import jalview.bin.Cache;
25    import jalview.datamodel.Alignment;
26    import jalview.datamodel.AlignmentI;
27    import jalview.datamodel.HiddenColumns;
28    import jalview.datamodel.PDBEntry;
29    import jalview.datamodel.SequenceI;
30    import jalview.gui.JalviewColourChooser.ColourChooserListener;
31    import jalview.gui.StructureViewer.ViewerType;
32    import jalview.gui.ViewSelectionMenu.ViewSetProvider;
33    import jalview.io.DataSourceType;
34    import jalview.io.JalviewFileChooser;
35    import jalview.io.JalviewFileView;
36    import jalview.jbgui.GStructureViewer;
37    import jalview.schemes.ColourSchemeI;
38    import jalview.schemes.ColourSchemes;
39    import jalview.structure.StructureMapping;
40    import jalview.structures.models.AAStructureBindingModel;
41    import jalview.util.MessageManager;
42   
43    import java.awt.Color;
44    import java.awt.Component;
45    import java.awt.event.ActionEvent;
46    import java.awt.event.ActionListener;
47    import java.awt.event.ItemEvent;
48    import java.awt.event.ItemListener;
49    import java.io.BufferedReader;
50    import java.io.File;
51    import java.io.FileOutputStream;
52    import java.io.FileReader;
53    import java.io.IOException;
54    import java.io.PrintWriter;
55    import java.util.ArrayList;
56    import java.util.List;
57    import java.util.Vector;
58   
59    import javax.swing.ButtonGroup;
60    import javax.swing.JCheckBoxMenuItem;
61    import javax.swing.JMenu;
62    import javax.swing.JMenuItem;
63    import javax.swing.JRadioButtonMenuItem;
64    import javax.swing.event.MenuEvent;
65    import javax.swing.event.MenuListener;
66   
67    /**
68    * Base class with common functionality for JMol, Chimera or other structure
69    * viewers.
70    *
71    * @author gmcarstairs
72    *
73    */
 
74    public abstract class StructureViewerBase extends GStructureViewer
75    implements Runnable, ViewSetProvider
76    {
77    /*
78    * names for colour options (additional to Jalview colour schemes)
79    */
 
80    enum ViewerColour
81    {
82    BySequence, ByChain, ChargeCysteine, ByViewer
83    }
84   
85    /**
86    * list of sequenceSet ids associated with the view
87    */
88    protected List<String> _aps = new ArrayList<>();
89   
90    /**
91    * list of alignment panels to use for superposition
92    */
93    protected Vector<AlignmentPanel> _alignwith = new Vector<>();
94   
95    /**
96    * list of alignment panels that are used for colouring structures by aligned
97    * sequences
98    */
99    protected Vector<AlignmentPanel> _colourwith = new Vector<>();
100   
101    private String viewId = null;
102   
103    private AlignmentPanel ap;
104   
105    protected boolean alignAddedStructures = false;
106   
107    protected volatile boolean _started = false;
108   
109    protected volatile boolean addingStructures = false;
110   
111    protected Thread worker = null;
112   
113    protected boolean allChainsSelected = false;
114   
115    protected JMenu viewSelectionMenu;
116   
117    /**
118    * set after sequence colouring has been applied for this structure viewer.
119    * used to determine if the final sequence/structure mapping has been
120    * determined
121    */
122    protected volatile boolean seqColoursApplied = false;
123   
124    /**
125    * Default constructor
126    */
 
127  10 toggle public StructureViewerBase()
128    {
129  10 super();
130    }
131   
132    /**
133    * @return true if added structures should be aligned to existing one(s)
134    */
 
135  0 toggle @Override
136    public boolean isAlignAddedStructures()
137    {
138  0 return alignAddedStructures;
139    }
140   
141    /**
142    *
143    * @param true
144    * if added structures should be aligned to existing one(s)
145    */
 
146  1 toggle @Override
147    public void setAlignAddedStructures(boolean alignAdded)
148    {
149  1 alignAddedStructures = alignAdded;
150    }
151   
152    /**
153    *
154    * @param ap2
155    * @return true if this Jmol instance is linked with the given alignPanel
156    */
 
157  1 toggle public boolean isLinkedWith(AlignmentPanel ap2)
158    {
159  1 return _aps.contains(ap2.av.getSequenceSetId());
160    }
161   
 
162  20 toggle public boolean isUsedforaligment(AlignmentPanel ap2)
163    {
164   
165  20 return (_alignwith != null) && _alignwith.contains(ap2);
166    }
167   
 
168  931 toggle public boolean isUsedforcolourby(AlignmentPanel ap2)
169    {
170  931 return (_colourwith != null) && _colourwith.contains(ap2);
171    }
172   
173    /**
174    *
175    * @return TRUE if the view is NOT being coloured by the alignment colours.
176    */
 
177  20 toggle public boolean isColouredByViewer()
178    {
179  20 return !getBinding().isColourBySequence();
180    }
181   
 
182  120 toggle public String getViewId()
183    {
184  120 if (viewId == null)
185    {
186  0 viewId = System.currentTimeMillis() + "." + this.hashCode();
187    }
188  120 return viewId;
189    }
190   
 
191  8 toggle protected void setViewId(String viewId)
192    {
193  8 this.viewId = viewId;
194    }
195   
196    public abstract String getStateInfo();
197   
 
198  80 toggle protected void buildActionMenu()
199    {
200  80 if (_alignwith == null)
201    {
202  0 _alignwith = new Vector<>();
203    }
204  80 if (_alignwith.size() == 0 && ap != null)
205    {
206  6 _alignwith.add(ap);
207    }
208  80 ;
209  80 for (Component c : viewerActionMenu.getMenuComponents())
210    {
211  87 if (c != alignStructs)
212    {
213  7 viewerActionMenu.remove((JMenuItem) c);
214    }
215    }
216    }
217   
 
218  265 toggle public AlignmentPanel getAlignmentPanel()
219    {
220  265 return ap;
221    }
222   
 
223  22 toggle protected void setAlignmentPanel(AlignmentPanel alp)
224    {
225  22 this.ap = alp;
226    }
227   
 
228  1 toggle @Override
229    public AlignmentPanel[] getAllAlignmentPanels()
230    {
231  1 AlignmentPanel[] t, list = new AlignmentPanel[0];
232  1 for (String setid : _aps)
233    {
234  1 AlignmentPanel[] panels = PaintRefresher.getAssociatedPanels(setid);
235  1 if (panels != null)
236    {
237  1 t = new AlignmentPanel[list.length + panels.length];
238  1 System.arraycopy(list, 0, t, 0, list.length);
239  1 System.arraycopy(panels, 0, t, list.length, panels.length);
240  1 list = t;
241    }
242    }
243   
244  1 return list;
245    }
246   
247    /**
248    * set the primary alignmentPanel reference and add another alignPanel to the
249    * list of ones to use for colouring and aligning
250    *
251    * @param nap
252    */
 
253  79 toggle public void addAlignmentPanel(AlignmentPanel nap)
254    {
255  79 if (getAlignmentPanel() == null)
256    {
257  10 setAlignmentPanel(nap);
258    }
259  79 if (!_aps.contains(nap.av.getSequenceSetId()))
260    {
261  14 _aps.add(nap.av.getSequenceSetId());
262    }
263    }
264   
265    /**
266    * remove any references held to the given alignment panel
267    *
268    * @param nap
269    */
 
270  82 toggle public void removeAlignmentPanel(AlignmentPanel nap)
271    {
272  82 try
273    {
274  82 _alignwith.remove(nap);
275  82 _colourwith.remove(nap);
276  82 if (getAlignmentPanel() == nap)
277    {
278  1 setAlignmentPanel(null);
279  1 for (AlignmentPanel aps : getAllAlignmentPanels())
280    {
281  0 if (aps != nap)
282    {
283  0 setAlignmentPanel(aps);
284  0 break;
285    }
286    }
287    }
288    } catch (Exception ex)
289    {
290    }
291  82 if (getAlignmentPanel() != null)
292    {
293  80 buildActionMenu();
294    }
295    }
296   
 
297  3 toggle public void useAlignmentPanelForSuperposition(AlignmentPanel nap)
298    {
299  3 addAlignmentPanel(nap);
300  3 if (!_alignwith.contains(nap))
301    {
302  2 _alignwith.add(nap);
303    }
304    }
305   
 
306  52 toggle public void excludeAlignmentPanelForSuperposition(AlignmentPanel nap)
307    {
308  52 if (_alignwith.contains(nap))
309    {
310  0 _alignwith.remove(nap);
311    }
312    }
313   
 
314  12 toggle public void useAlignmentPanelForColourbyseq(AlignmentPanel nap,
315    boolean enableColourBySeq)
316    {
317  12 useAlignmentPanelForColourbyseq(nap);
318  12 getBinding().setColourBySequence(enableColourBySeq);
319  12 seqColour.setSelected(enableColourBySeq);
320  12 viewerColour.setSelected(!enableColourBySeq);
321    }
322   
 
323  14 toggle public void useAlignmentPanelForColourbyseq(AlignmentPanel nap)
324    {
325  14 addAlignmentPanel(nap);
326  14 if (!_colourwith.contains(nap))
327    {
328  14 _colourwith.add(nap);
329    }
330    }
331   
 
332  40 toggle public void excludeAlignmentPanelForColourbyseq(AlignmentPanel nap)
333    {
334  40 if (_colourwith.contains(nap))
335    {
336  0 _colourwith.remove(nap);
337    }
338    }
339   
340    public abstract ViewerType getViewerType();
341   
342    protected abstract IProgressIndicator getIProgressIndicator();
343   
344    /**
345    * add a new structure (with associated sequences and chains) to this viewer,
346    * retrieving it if necessary first.
347    *
348    * @param pdbentry
349    * @param seqs
350    * @param chains
351    * @param align
352    * if true, new structure(s) will be aligned using associated
353    * alignment
354    * @param alignFrame
355    */
 
356  1 toggle protected void addStructure(final PDBEntry pdbentry,
357    final SequenceI[] seqs, final String[] chains,
358    final IProgressIndicator alignFrame)
359    {
360  1 if (pdbentry.getFile() == null)
361    {
362  0 if (worker != null && worker.isAlive())
363    {
364    // a retrieval is in progress, wait around and add ourselves to the
365    // queue.
366  0 new Thread(new Runnable()
367    {
 
368  0 toggle @Override
369    public void run()
370    {
371  0 while (worker != null && worker.isAlive() && _started)
372    {
373  0 try
374    {
375  0 Thread.sleep(100 + ((int) Math.random() * 100));
376   
377    } catch (Exception e)
378    {
379    }
380    }
381    // and call ourselves again.
382  0 addStructure(pdbentry, seqs, chains, alignFrame);
383    }
384    }).start();
385  0 return;
386    }
387    }
388    // otherwise, start adding the structure.
389  1 getBinding().addSequenceAndChain(new PDBEntry[] { pdbentry },
390    new SequenceI[][]
391    { seqs }, new String[][] { chains });
392  1 addingStructures = true;
393  1 _started = false;
394  1 worker = new Thread(this);
395  1 worker.start();
396  1 return;
397    }
398   
 
399  1 toggle protected boolean hasPdbId(String pdbId)
400    {
401  1 return getBinding().hasPdbId(pdbId);
402    }
403   
404    /**
405    * Returns a list of any viewer of the instantiated type. The list is
406    * restricted to those linked to the given alignment panel if it is not null.
407    */
 
408  0 toggle protected List<StructureViewerBase> getViewersFor(AlignmentPanel alp)
409    {
410  0 return Desktop.instance.getStructureViewers(alp, this.getClass());
411    }
412   
 
413  1 toggle @Override
414    public void addToExistingViewer(PDBEntry pdbentry, SequenceI[] seq,
415    String[] chains, final AlignmentViewPanel apanel, String pdbId)
416    {
417    /*
418    * JAL-1742 exclude view with this structure already mapped (don't offer
419    * to align chain B to chain A of the same structure); code may defend
420    * against this possibility before we reach here
421    */
422  1 if (hasPdbId(pdbId))
423    {
424  0 return;
425    }
426  1 AlignmentPanel alignPanel = (AlignmentPanel) apanel; // Implementation error if this
427    // cast fails
428  1 useAlignmentPanelForSuperposition(alignPanel);
429  1 addStructure(pdbentry, seq, chains, alignPanel.alignFrame);
430    }
431   
432    /**
433    * Adds mappings for the given sequences to an already opened PDB structure,
434    * and updates any viewers that have the PDB file
435    *
436    * @param seq
437    * @param chains
438    * @param apanel
439    * @param pdbFilename
440    */
 
441  0 toggle public void addSequenceMappingsToStructure(SequenceI[] seq,
442    String[] chains, final AlignmentViewPanel alpanel,
443    String pdbFilename)
444    {
445  0 AlignmentPanel apanel = (AlignmentPanel) alpanel;
446   
447    // TODO : Fix multiple seq to one chain issue here.
448    /*
449    * create the mappings
450    */
451  0 apanel.getStructureSelectionManager().setMapping(seq, chains,
452    pdbFilename, DataSourceType.FILE, getIProgressIndicator());
453   
454    /*
455    * alert the FeatureRenderer to show new (PDB RESNUM) features
456    */
457  0 if (apanel.getSeqPanel().seqCanvas.fr != null)
458    {
459  0 apanel.getSeqPanel().seqCanvas.fr.featuresAdded();
460    // note - we don't do a refresh for structure here because we do it
461    // explicitly for all panels later on
462  0 apanel.paintAlignment(true, false);
463    }
464   
465    /*
466    * add the sequences to any other viewers (of the same type) for this pdb
467    * file
468    */
469    // JBPNOTE: this looks like a binding routine, rather than a gui routine
470  0 for (StructureViewerBase viewer : getViewersFor(null))
471    {
472  0 AAStructureBindingModel bindingModel = viewer.getBinding();
473  0 for (int pe = 0; pe < bindingModel.getPdbCount(); pe++)
474    {
475  0 if (bindingModel.getPdbEntry(pe).getFile().equals(pdbFilename))
476    {
477  0 bindingModel.addSequence(pe, seq);
478  0 viewer.addAlignmentPanel(apanel);
479    /*
480    * add it to the set of alignments used for colouring structure by
481    * sequence
482    */
483  0 viewer.useAlignmentPanelForColourbyseq(apanel);
484  0 viewer.buildActionMenu();
485  0 apanel.getStructureSelectionManager()
486    .sequenceColoursChanged(apanel);
487  0 break;
488    }
489    }
490    }
491    }
492   
 
493  1 toggle @Override
494    public boolean addAlreadyLoadedFile(SequenceI[] seq, String[] chains,
495    final AlignmentViewPanel apanel, String pdbId)
496    {
497  1 String alreadyMapped = apanel.getStructureSelectionManager()
498    .alreadyMappedToFile(pdbId);
499   
500  1 if (alreadyMapped == null)
501    {
502  1 return false;
503    }
504   
505  0 addSequenceMappingsToStructure(seq, chains, apanel, alreadyMapped);
506  0 return true;
507    }
508   
 
509  11 toggle void setChainMenuItems(List<String> chainNames)
510    {
511  11 chainMenu.removeAll();
512  11 if (chainNames == null || chainNames.isEmpty())
513    {
514  0 return;
515    }
516  11 JMenuItem menuItem = new JMenuItem(
517    MessageManager.getString("label.all"));
518  11 menuItem.addActionListener(new ActionListener()
519    {
 
520  0 toggle @Override
521    public void actionPerformed(ActionEvent evt)
522    {
523  0 allChainsSelected = true;
524  0 for (int i = 0; i < chainMenu.getItemCount(); i++)
525    {
526  0 if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
527    {
528  0 ((JCheckBoxMenuItem) chainMenu.getItem(i)).setSelected(true);
529    }
530    }
531  0 showSelectedChains();
532  0 allChainsSelected = false;
533    }
534    });
535   
536  11 chainMenu.add(menuItem);
537   
538  11 for (String chain : chainNames)
539    {
540  21 menuItem = new JCheckBoxMenuItem(chain, true);
541  21 menuItem.addItemListener(new ItemListener()
542    {
 
543  0 toggle @Override
544    public void itemStateChanged(ItemEvent evt)
545    {
546  0 if (!allChainsSelected)
547    {
548  0 showSelectedChains();
549    }
550    }
551    });
552   
553  21 chainMenu.add(menuItem);
554    }
555    }
556   
557    abstract void showSelectedChains();
558   
559    /**
560    * Action on selecting one of Jalview's registered colour schemes
561    */
 
562  0 toggle @Override
563    public void changeColour_actionPerformed(String colourSchemeName)
564    {
565  0 AlignmentI al = getAlignmentPanel().av.getAlignment();
566  0 ColourSchemeI cs = ColourSchemes.getInstance()
567    .getColourScheme(colourSchemeName, al, null);
568  0 getBinding().setJalviewColourScheme(cs);
569    }
570   
571    /**
572    * Builds the colour menu
573    */
 
574  10 toggle protected void buildColourMenu()
575    {
576  10 colourMenu.removeAll();
577  10 AlignmentI al = getAlignmentPanel().av.getAlignment();
578   
579    /*
580    * add colour by sequence, by chain, by charge and cysteine
581    */
582  10 colourMenu.add(seqColour);
583  10 colourMenu.add(chainColour);
584  10 colourMenu.add(chargeColour);
585  10 chargeColour.setEnabled(!al.isNucleotide());
586   
587    /*
588    * add all 'simple' (per-residue) colour schemes registered to Jalview
589    */
590  10 ButtonGroup itemGroup = ColourMenuHelper.addMenuItems(colourMenu, this,
591    al, true);
592   
593    /*
594    * add 'colour by viewer' (menu item text is set in subclasses)
595    */
596  10 viewerColour.setSelected(false);
597  10 viewerColour.addActionListener(new ActionListener()
598    {
 
599  0 toggle @Override
600    public void actionPerformed(ActionEvent actionEvent)
601    {
602  0 viewerColour_actionPerformed(actionEvent);
603    }
604    });
605  10 colourMenu.add(viewerColour);
606   
607    /*
608    * add 'set background colour'
609    */
610  10 JMenuItem backGround = new JMenuItem();
611  10 backGround
612    .setText(MessageManager.getString("action.background_colour"));
613  10 backGround.addActionListener(new ActionListener()
614    {
 
615  0 toggle @Override
616    public void actionPerformed(ActionEvent actionEvent)
617    {
618  0 background_actionPerformed(actionEvent);
619    }
620    });
621  10 colourMenu.add(backGround);
622   
623    /*
624    * add colour buttons to a group so their selection is
625    * mutually exclusive (background colour is a separate option)
626    */
627  10 itemGroup.add(seqColour);
628  10 itemGroup.add(chainColour);
629  10 itemGroup.add(chargeColour);
630  10 itemGroup.add(viewerColour);
631    }
632   
633    /**
634    * Construct menu items
635    */
 
636  10 toggle protected void initMenus()
637    {
638  10 AAStructureBindingModel binding = getBinding();
639   
640  10 seqColour = new JRadioButtonMenuItem();
641  10 seqColour.setText(MessageManager.getString("action.by_sequence"));
642  10 seqColour.setName(ViewerColour.BySequence.name());
643  10 seqColour.setSelected(binding.isColourBySequence());
644  10 seqColour.addActionListener(new ActionListener()
645    {
 
646  0 toggle @Override
647    public void actionPerformed(ActionEvent actionEvent)
648    {
649  0 seqColour_actionPerformed(actionEvent);
650    }
651    });
652   
653  10 chainColour = new JRadioButtonMenuItem();
654  10 chainColour.setText(MessageManager.getString("action.by_chain"));
655  10 chainColour.setName(ViewerColour.ByChain.name());
656  10 chainColour.addActionListener(new ActionListener()
657    {
 
658  0 toggle @Override
659    public void actionPerformed(ActionEvent actionEvent)
660    {
661  0 chainColour_actionPerformed(actionEvent);
662    }
663    });
664   
665  10 chargeColour = new JRadioButtonMenuItem();
666  10 chargeColour.setText(MessageManager.getString("label.charge_cysteine"));
667  10 chargeColour.setName(ViewerColour.ChargeCysteine.name());
668  10 chargeColour.addActionListener(new ActionListener()
669    {
 
670  0 toggle @Override
671    public void actionPerformed(ActionEvent actionEvent)
672    {
673  0 chargeColour_actionPerformed(actionEvent);
674    }
675    });
676   
677  10 viewerColour = new JRadioButtonMenuItem();
678    // text is set in overrides of this method
679  10 viewerColour.setName(ViewerColour.ByViewer.name());
680  10 viewerColour.setSelected(!binding.isColourBySequence());
681   
682  10 if (_colourwith == null)
683    {
684  0 _colourwith = new Vector<>();
685    }
686  10 if (_alignwith == null)
687    {
688  0 _alignwith = new Vector<>();
689    }
690   
691  10 ViewSelectionMenu seqColourBy = new ViewSelectionMenu(
692    MessageManager.getString("label.colour_by"), this, _colourwith,
693    new ItemListener()
694    {
 
695  0 toggle @Override
696    public void itemStateChanged(ItemEvent e)
697    {
698  0 if (!seqColour.isSelected())
699    {
700  0 seqColour.doClick();
701    }
702    else
703    {
704    // update the Chimera display now.
705  0 seqColour_actionPerformed(null);
706    }
707    }
708    });
709  10 viewMenu.add(seqColourBy);
710   
711  10 final ItemListener handler = new ItemListener()
712    {
 
713  10 toggle @Override
714    public void itemStateChanged(ItemEvent e)
715    {
716  10 alignStructs.setEnabled(!_alignwith.isEmpty());
717  10 alignStructs.setToolTipText(MessageManager.formatMessage(
718    "label.align_structures_using_linked_alignment_views",
719    _alignwith.size()));
720    }
721    };
722  10 viewSelectionMenu = new ViewSelectionMenu(
723    MessageManager.getString("label.superpose_with"), this,
724    _alignwith, handler);
725  10 handler.itemStateChanged(null);
726  10 viewerActionMenu.add(viewSelectionMenu, 0);
727  10 viewerActionMenu.addMenuListener(new MenuListener()
728    {
 
729  0 toggle @Override
730    public void menuSelected(MenuEvent e)
731    {
732  0 handler.itemStateChanged(null);
733    }
734   
 
735  0 toggle @Override
736    public void menuDeselected(MenuEvent e)
737    {
738    }
739   
 
740  0 toggle @Override
741    public void menuCanceled(MenuEvent e)
742    {
743    }
744    });
745   
746  10 buildColourMenu();
747    }
748   
 
749  0 toggle @Override
750    public void setJalviewColourScheme(ColourSchemeI cs)
751    {
752  0 getBinding().setJalviewColourScheme(cs);
753    }
754   
755    /**
756    * Sends commands to the structure viewer to superimpose structures based on
757    * currently associated alignments. May optionally return an error message for
758    * the operation.
759    */
 
760  0 toggle @Override
761    protected String alignStructs_actionPerformed(ActionEvent actionEvent)
762    {
763  0 return alignStructs_withAllAlignPanels();
764    }
765   
 
766  1 toggle protected String alignStructs_withAllAlignPanels()
767    {
768  1 if (getAlignmentPanel() == null)
769    {
770  0 return null;
771    }
772   
773  1 if (_alignwith.size() == 0)
774    {
775  0 _alignwith.add(getAlignmentPanel());
776    }
777   
778  1 String reply = null;
779  1 try
780    {
781  1 AlignmentI[] als = new Alignment[_alignwith.size()];
782  1 HiddenColumns[] alc = new HiddenColumns[_alignwith.size()];
783  1 int[] alm = new int[_alignwith.size()];
784  1 int a = 0;
785   
786  1 for (AlignmentPanel alignPanel : _alignwith)
787    {
788  1 als[a] = alignPanel.av.getAlignment();
789  1 alm[a] = -1;
790  1 alc[a++] = alignPanel.av.getAlignment().getHiddenColumns();
791    }
792  1 reply = getBinding().superposeStructures(als, alm, alc);
793  0 if (reply != null)
794    {
795  0 String text = MessageManager
796    .formatMessage("error.superposition_failed", reply);
797  0 statusBar.setText(text);
798    }
799    } catch (Exception e)
800    {
801  1 StringBuffer sp = new StringBuffer();
802  1 for (AlignmentPanel alignPanel : _alignwith)
803    {
804  0 sp.append("'" + alignPanel.alignFrame.getTitle() + "' ");
805    }
806  1 Cache.log.info("Couldn't align structures with the " + sp.toString()
807    + "associated alignment panels.", e);
808    }
809  1 return reply;
810    }
811   
812    /**
813    * Opens a colour chooser dialog, and applies the chosen colour to the
814    * background of the structure viewer
815    */
 
816  0 toggle @Override
817    public void background_actionPerformed(ActionEvent actionEvent)
818    {
819  0 String ttl = MessageManager.getString("label.select_background_colour");
820  0 ColourChooserListener listener = new ColourChooserListener()
821    {
 
822  0 toggle @Override
823    public void colourSelected(Color c)
824    {
825  0 getBinding().setBackgroundColour(c);
826    }
827    };
828  0 JalviewColourChooser.showColourChooser(this, ttl, null, listener);
829    }
830   
 
831  0 toggle @Override
832    public void viewerColour_actionPerformed(ActionEvent actionEvent)
833    {
834  0 if (viewerColour.isSelected())
835    {
836    // disable automatic sequence colouring.
837  0 getBinding().setColourBySequence(false);
838    }
839    }
840   
 
841  0 toggle @Override
842    public void chainColour_actionPerformed(ActionEvent actionEvent)
843    {
844  0 chainColour.setSelected(true);
845  0 getBinding().colourByChain();
846    }
847   
 
848  0 toggle @Override
849    public void chargeColour_actionPerformed(ActionEvent actionEvent)
850    {
851  0 chargeColour.setSelected(true);
852  0 getBinding().colourByCharge();
853    }
854   
 
855  11 toggle @Override
856    public void seqColour_actionPerformed(ActionEvent actionEvent)
857    {
858  11 AAStructureBindingModel binding = getBinding();
859  11 binding.setColourBySequence(seqColour.isSelected());
860  11 if (_colourwith == null)
861    {
862  0 _colourwith = new Vector<>();
863    }
864  11 if (binding.isColourBySequence())
865    {
866  3 if (!binding.isLoadingFromArchive())
867    {
868  3 if (_colourwith.size() == 0 && getAlignmentPanel() != null)
869    {
870    // Make the currently displayed alignment panel the associated view
871  0 _colourwith.add(getAlignmentPanel().alignFrame.alignPanel);
872    }
873    }
874    // Set the colour using the current view for the associated alignframe
875  3 for (AlignmentPanel alignPanel : _colourwith)
876    {
877  3 binding.colourBySequence(alignPanel);
878    }
879  3 seqColoursApplied = true;
880    }
881    }
882   
 
883  0 toggle @Override
884    public void pdbFile_actionPerformed(ActionEvent actionEvent)
885    {
886    // TODO: JAL-3048 not needed for Jalview-JS - save PDB file
887  0 JalviewFileChooser chooser = new JalviewFileChooser(
888    Cache.getProperty("LAST_DIRECTORY"));
889   
890  0 chooser.setFileView(new JalviewFileView());
891  0 chooser.setDialogTitle(MessageManager.getString("label.save_pdb_file"));
892  0 chooser.setToolTipText(MessageManager.getString("action.save"));
893   
894  0 int value = chooser.showSaveDialog(this);
895   
896  0 if (value == JalviewFileChooser.APPROVE_OPTION)
897    {
898  0 BufferedReader in = null;
899  0 try
900    {
901    // TODO: cope with multiple PDB files in view
902  0 in = new BufferedReader(
903    new FileReader(getBinding().getStructureFiles()[0]));
904  0 File outFile = chooser.getSelectedFile();
905   
906  0 PrintWriter out = new PrintWriter(new FileOutputStream(outFile));
907  0 String data;
908  0 while ((data = in.readLine()) != null)
909    {
910  0 if (!(data.indexOf("<PRE>") > -1 || data.indexOf("</PRE>") > -1))
911    {
912  0 out.println(data);
913    }
914    }
915  0 out.close();
916    } catch (Exception ex)
917    {
918  0 ex.printStackTrace();
919    } finally
920    {
921  0 if (in != null)
922    {
923  0 try
924    {
925  0 in.close();
926    } catch (IOException e)
927    {
928    // ignore
929    }
930    }
931    }
932    }
933    }
934   
 
935  0 toggle @Override
936    public void viewMapping_actionPerformed(ActionEvent actionEvent)
937    {
938  0 CutAndPasteTransfer cap = new CutAndPasteTransfer();
939  0 try
940    {
941  0 cap.appendText(getBinding().printMappings());
942    } catch (OutOfMemoryError e)
943    {
944  0 new OOMWarning(
945    "composing sequence-structure alignments for display in text box.",
946    e);
947  0 cap.dispose();
948  0 return;
949    }
950  0 Desktop.addInternalFrame(cap,
951    MessageManager.getString("label.pdb_sequence_mapping"), 550,
952    600);
953    }
954   
955    protected abstract String getViewerName();
956   
957    /**
958    * Configures the title and menu items of the viewer panel.
959    */
 
960  11 toggle @Override
961    public void updateTitleAndMenus()
962    {
963  11 AAStructureBindingModel binding = getBinding();
964  11 if (binding.hasFileLoadingError())
965    {
966  0 repaint();
967  0 return;
968    }
969  11 setChainMenuItems(binding.getChainNames());
970   
971  11 this.setTitle(binding.getViewerTitle(getViewerName(), true));
972   
973    /*
974    * enable 'Superpose with' if more than one mapped structure
975    */
976  11 viewSelectionMenu.setEnabled(false);
977  11 if (getBinding().getStructureFiles().length > 1
978    && getBinding().getSequence().length > 1)
979    {
980  1 viewSelectionMenu.setEnabled(true);
981    }
982   
983    /*
984    * Show action menu if it has any enabled items
985    */
986  11 viewerActionMenu.setVisible(false);
987  29 for (int i = 0; i < viewerActionMenu.getItemCount(); i++)
988    {
989  21 if (viewerActionMenu.getItem(i).isEnabled())
990    {
991  3 viewerActionMenu.setVisible(true);
992  3 break;
993    }
994    }
995   
996  11 if (!binding.isLoadingFromArchive())
997    {
998  11 seqColour_actionPerformed(null);
999    }
1000    }
1001   
 
1002  0 toggle @Override
1003    public String toString()
1004    {
1005  0 return getTitle();
1006    }
1007   
 
1008  3 toggle @Override
1009    public boolean hasMapping()
1010    {
1011  3 if (worker != null && (addingStructures || _started))
1012    {
1013  2 return false;
1014    }
1015  1 if (getBinding() == null)
1016    {
1017  0 if (_aps == null || _aps.size() == 0)
1018    {
1019    // viewer has been closed, but we did at some point run.
1020  0 return true;
1021    }
1022  0 return false;
1023    }
1024  1 String[] pdbids = getBinding().getStructureFiles();
1025  1 if (pdbids == null)
1026    {
1027  0 return false;
1028    }
1029  1 int p=0;
1030  1 for (String pdbid:pdbids) {
1031  2 StructureMapping sm[] = getBinding().getSsm().getMapping(pdbid);
1032  2 if (sm!=null && sm.length>0 && sm[0]!=null) {
1033  2 p++;
1034    }
1035    }
1036    // only return true if there is a mapping for every structure file we have loaded
1037  1 if (p == 0 || p != pdbids.length)
1038    {
1039  0 return false;
1040    }
1041    // and that coloring has been applied
1042  1 return seqColoursApplied;
1043    }
1044   
 
1045  1 toggle @Override
1046    public void raiseViewer()
1047    {
1048  1 toFront();
1049    }
1050   
1051    }