2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
23 import jalview.datamodel.PDBEntry;
24 import jalview.datamodel.SequenceI;
25 import jalview.gui.StructureViewer.ViewerType;
26 import jalview.gui.ViewSelectionMenu.ViewSetProvider;
27 import jalview.io.DataSourceType;
28 import jalview.jbgui.GStructureViewer;
29 import jalview.structures.models.AAStructureBindingModel;
30 import jalview.util.MessageManager;
32 import java.awt.Component;
33 import java.awt.event.ActionEvent;
34 import java.awt.event.ActionListener;
35 import java.awt.event.ItemEvent;
36 import java.awt.event.ItemListener;
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.Vector;
41 import javax.swing.JCheckBoxMenuItem;
42 import javax.swing.JMenuItem;
43 import javax.swing.JOptionPane;
46 * Base class with common functionality for JMol, Chimera or other structure
52 public abstract class StructureViewerBase extends GStructureViewer
53 implements Runnable, ViewSetProvider
57 * list of sequenceSet ids associated with the view
59 protected List<String> _aps = new ArrayList<String>();
62 * list of alignment panels to use for superposition
64 protected Vector<AlignmentPanel> _alignwith = new Vector<AlignmentPanel>();
67 * list of alignment panels that are used for colouring structures by aligned
70 protected Vector<AlignmentPanel> _colourwith = new Vector<AlignmentPanel>();
72 private String viewId = null;
74 private AlignmentPanel ap;
76 protected boolean alignAddedStructures = false;
78 protected boolean _started = false;
80 protected boolean addingStructures = false;
82 protected Thread worker = null;
84 protected boolean allChainsSelected = false;
89 * @return true if this Jmol instance is linked with the given alignPanel
91 public boolean isLinkedWith(AlignmentPanel ap2)
93 return _aps.contains(ap2.av.getSequenceSetId());
96 public boolean isUsedforaligment(AlignmentPanel ap2)
99 return (_alignwith != null) && _alignwith.contains(ap2);
102 public boolean isUsedforcolourby(AlignmentPanel ap2)
104 return (_colourwith != null) && _colourwith.contains(ap2);
109 * @return TRUE if the view is NOT being coloured by the alignment colours.
111 public boolean isColouredByViewer()
113 return !getBinding().isColourBySequence();
116 public String getViewId()
120 viewId = System.currentTimeMillis() + "." + this.hashCode();
125 protected void setViewId(String viewId)
127 this.viewId = viewId;
130 public abstract String getStateInfo();
132 protected void buildActionMenu()
134 if (_alignwith == null)
136 _alignwith = new Vector<AlignmentPanel>();
138 if (_alignwith.size() == 0 && ap != null)
143 for (Component c : viewerActionMenu.getMenuComponents())
145 if (c != alignStructs)
147 viewerActionMenu.remove((JMenuItem) c);
152 public AlignmentPanel getAlignmentPanel()
157 protected void setAlignmentPanel(AlignmentPanel alp)
163 public AlignmentPanel[] getAllAlignmentPanels()
165 AlignmentPanel[] t, list = new AlignmentPanel[0];
166 for (String setid : _aps)
168 AlignmentPanel[] panels = PaintRefresher.getAssociatedPanels(setid);
171 t = new AlignmentPanel[list.length + panels.length];
172 System.arraycopy(list, 0, t, 0, list.length);
173 System.arraycopy(panels, 0, t, list.length, panels.length);
182 * set the primary alignmentPanel reference and add another alignPanel to the
183 * list of ones to use for colouring and aligning
187 public void addAlignmentPanel(AlignmentPanel nap)
189 if (getAlignmentPanel() == null)
191 setAlignmentPanel(nap);
193 if (!_aps.contains(nap.av.getSequenceSetId()))
195 _aps.add(nap.av.getSequenceSetId());
200 * remove any references held to the given alignment panel
204 public void removeAlignmentPanel(AlignmentPanel nap)
208 _alignwith.remove(nap);
209 _colourwith.remove(nap);
210 if (getAlignmentPanel() == nap)
212 setAlignmentPanel(null);
213 for (AlignmentPanel aps : getAllAlignmentPanels())
217 setAlignmentPanel(aps);
222 } catch (Exception ex)
225 if (getAlignmentPanel() != null)
231 public void useAlignmentPanelForSuperposition(AlignmentPanel nap)
233 addAlignmentPanel(nap);
234 if (!_alignwith.contains(nap))
240 public void excludeAlignmentPanelForSuperposition(AlignmentPanel nap)
242 if (_alignwith.contains(nap))
244 _alignwith.remove(nap);
248 public void useAlignmentPanelForColourbyseq(AlignmentPanel nap,
249 boolean enableColourBySeq)
251 useAlignmentPanelForColourbyseq(nap);
252 getBinding().setColourBySequence(enableColourBySeq);
253 seqColour.setSelected(enableColourBySeq);
254 viewerColour.setSelected(!enableColourBySeq);
257 public void useAlignmentPanelForColourbyseq(AlignmentPanel nap)
259 addAlignmentPanel(nap);
260 if (!_colourwith.contains(nap))
262 _colourwith.add(nap);
266 public void excludeAlignmentPanelForColourbyseq(AlignmentPanel nap)
268 if (_colourwith.contains(nap))
270 _colourwith.remove(nap);
274 public abstract ViewerType getViewerType();
276 protected abstract AAStructureBindingModel getBindingModel();
279 * add a new structure (with associated sequences and chains) to this viewer,
280 * retrieving it if necessary first.
286 * if true, new structure(s) will be aligned using associated
290 protected void addStructure(final PDBEntry pdbentry,
291 final SequenceI[] seqs, final String[] chains,
292 final boolean align, final IProgressIndicator alignFrame)
294 if (pdbentry.getFile() == null)
296 if (worker != null && worker.isAlive())
298 // a retrieval is in progress, wait around and add ourselves to the
300 new Thread(new Runnable()
305 while (worker != null && worker.isAlive() && _started)
309 Thread.sleep(100 + ((int) Math.random() * 100));
311 } catch (Exception e)
315 // and call ourselves again.
316 addStructure(pdbentry, seqs, chains, align, alignFrame);
322 // otherwise, start adding the structure.
323 getBindingModel().addSequenceAndChain(new PDBEntry[] { pdbentry },
324 new SequenceI[][] { seqs }, new String[][] { chains });
325 addingStructures = true;
327 alignAddedStructures = align;
328 worker = new Thread(this);
334 * Presents a dialog with the option to add an align a structure to an
335 * existing structure view
339 * @return YES, NO or CANCEL JvOptionPane code
341 protected int chooseAlignStructureToViewer(String pdbId,
342 StructureViewerBase view)
344 int option = JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
345 MessageManager.formatMessage("label.add_pdbentry_to_view",
346 new Object[] { pdbId, view.getTitle() }),
348 .getString("label.align_to_existing_structure_view"),
349 JvOptionPane.YES_NO_CANCEL_OPTION);
353 protected abstract boolean hasPdbId(String pdbId);
355 protected abstract List<StructureViewerBase> getViewersFor(
359 * Check for any existing views involving this alignment and give user the
360 * option to add and align this molecule to one of them
367 * @return true if user adds to a view, or cancels entirely, else false
369 protected boolean addToExistingViewer(PDBEntry pdbentry, SequenceI[] seq,
370 String[] chains, final AlignmentPanel apanel, String pdbId)
372 for (StructureViewerBase view : getViewersFor(apanel))
374 // TODO: highlight the view somehow
376 * JAL-1742 exclude view with this structure already mapped (don't offer
377 * to align chain B to chain A of the same structure)
379 if (view.hasPdbId(pdbId))
383 int option = chooseAlignStructureToViewer(pdbId, view);
384 if (option == JvOptionPane.CANCEL_OPTION)
388 else if (option == JvOptionPane.YES_OPTION)
390 view.useAlignmentPanelForSuperposition(apanel);
391 view.addStructure(pdbentry, seq, chains, true, apanel.alignFrame);
396 // NO_OPTION - offer the next viewer if any
401 * nothing offered and selected
407 * Adds mappings for the given sequences to an already opened PDB structure,
408 * and updates any viewers that have the PDB file
415 protected void addSequenceMappingsToStructure(SequenceI[] seq,
416 String[] chains, final AlignmentPanel apanel, String pdbFilename)
418 // TODO : Fix multiple seq to one chain issue here.
420 * create the mappings
422 apanel.getStructureSelectionManager().setMapping(seq, chains,
423 pdbFilename, DataSourceType.FILE);
426 * alert the FeatureRenderer to show new (PDB RESNUM) features
428 if (apanel.getSeqPanel().seqCanvas.fr != null)
430 apanel.getSeqPanel().seqCanvas.fr.featuresAdded();
431 apanel.paintAlignment(true);
435 * add the sequences to any other viewers (of the same type) for this pdb
438 // JBPNOTE: this looks like a binding routine, rather than a gui routine
439 for (StructureViewerBase viewer : getViewersFor(null))
441 AAStructureBindingModel bindingModel = viewer.getBindingModel();
442 for (int pe = 0; pe < bindingModel.getPdbCount(); pe++)
444 if (bindingModel.getPdbEntry(pe).getFile().equals(pdbFilename))
446 bindingModel.addSequence(pe, seq);
447 viewer.addAlignmentPanel(apanel);
449 * add it to the set of alignments used for colouring structure by
452 viewer.useAlignmentPanelForColourbyseq(apanel);
453 viewer.buildActionMenu();
454 apanel.getStructureSelectionManager().sequenceColoursChanged(
463 * Check if the PDB file is already loaded, if so offer to add it to the
470 * @return true if the user chooses to add to a viewer, or to cancel entirely
472 protected boolean addAlreadyLoadedFile(SequenceI[] seq, String[] chains,
473 final AlignmentPanel apanel, String pdbId)
475 boolean finished = false;
476 String alreadyMapped = apanel.getStructureSelectionManager()
477 .alreadyMappedToFile(pdbId);
479 if (alreadyMapped != null)
482 * the PDB file is already loaded
484 int option = JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
485 MessageManager.formatMessage(
486 "label.pdb_entry_is_already_displayed",
487 new Object[] { pdbId }), MessageManager
489 "label.map_sequences_to_visible_window",
490 new Object[] { pdbId }),
491 JvOptionPane.YES_NO_CANCEL_OPTION);
492 if (option == JvOptionPane.CANCEL_OPTION)
496 else if (option == JvOptionPane.YES_OPTION)
498 addSequenceMappingsToStructure(seq, chains, apanel, alreadyMapped);
505 void setChainMenuItems(List<String> chainNames)
507 chainMenu.removeAll();
508 if (chainNames == null || chainNames.isEmpty())
512 JMenuItem menuItem = new JMenuItem(
513 MessageManager.getString("label.all"));
514 menuItem.addActionListener(new ActionListener()
517 public void actionPerformed(ActionEvent evt)
519 allChainsSelected = true;
520 for (int i = 0; i < chainMenu.getItemCount(); i++)
522 if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
524 ((JCheckBoxMenuItem) chainMenu.getItem(i)).setSelected(true);
527 showSelectedChains();
528 allChainsSelected = false;
532 chainMenu.add(menuItem);
534 for (String chain : chainNames)
536 menuItem = new JCheckBoxMenuItem(chain, true);
537 menuItem.addItemListener(new ItemListener()
540 public void itemStateChanged(ItemEvent evt)
542 if (!allChainsSelected)
544 showSelectedChains();
549 chainMenu.add(menuItem);
553 abstract void showSelectedChains();