From 2373f90e6077de127c55ec6cb7671d8ba2436684 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Wed, 19 Aug 2015 09:39:26 +0100 Subject: [PATCH] JAL-1742 suppress 'add chain' option for Jmol, pull up shared code for Jmol/Chimera --- .../edu/ucsf/rbvi/strucviz2/ChimeraManager.java | 2 +- src/jalview/ext/jmol/JalviewJmolBinding.java | 15 - .../ext/rbvi/chimera/JalviewChimeraBinding.java | 15 - src/jalview/gui/AppJmol.java | 201 +++----------- src/jalview/gui/ChimeraViewFrame.java | 291 ++++---------------- src/jalview/gui/StructureViewerBase.java | 241 +++++++++++++++- .../structures/models/AAStructureBindingModel.java | 12 + .../ext/rbvi/chimera/JalviewChimeraView.java | 35 ++- .../models/AAStructureBindingModelTest.java | 2 +- 9 files changed, 371 insertions(+), 443 deletions(-) diff --git a/src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java b/src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java index 7cc72cf..d53d498 100644 --- a/src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java +++ b/src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java @@ -836,7 +836,7 @@ public class ChimeraManager } } catch (Exception e) { - logger.error("REST call " + command + " failed: " + e.getMessage()); + logger.error("REST call '" + command + "' failed: " + e.getMessage()); } finally { if (response != null) diff --git a/src/jalview/ext/jmol/JalviewJmolBinding.java b/src/jalview/ext/jmol/JalviewJmolBinding.java index 296892c..8743554 100644 --- a/src/jalview/ext/jmol/JalviewJmolBinding.java +++ b/src/jalview/ext/jmol/JalviewJmolBinding.java @@ -63,11 +63,6 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel implements JmolStatusListener, JmolSelectionListener, ComponentListener { - /* - * state flag used to check if the Jmol viewer's paint method can be called - */ - private boolean finishedInit = false; - boolean allChainsSelected = false; /* @@ -1411,16 +1406,6 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel return null; } - public boolean isFinishedInit() - { - return finishedInit; - } - - public void setFinishedInit(boolean finishedInit) - { - this.finishedInit = finishedInit; - } - /** * */ diff --git a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java index cee271a..b648bea 100644 --- a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java +++ b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java @@ -86,11 +86,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel */ private boolean loadingFinished = true; - /* - * state flag used to check if the Chimera viewer's paint method can be called - */ - private boolean finishedInit = false; - public String fileLoadingError; /* @@ -1079,16 +1074,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel return true; } - public boolean isFinishedInit() - { - return finishedInit; - } - - public void setFinishedInit(boolean finishedInit) - { - this.finishedInit = finishedInit; - } - /** * Returns a list of chains mapped in this viewer. Note this list is not * currently scoped per structure. diff --git a/src/jalview/gui/AppJmol.java b/src/jalview/gui/AppJmol.java index bd1cc88..dcd4f7d 100644 --- a/src/jalview/gui/AppJmol.java +++ b/src/jalview/gui/AppJmol.java @@ -27,7 +27,6 @@ import jalview.datamodel.ColumnSelection; import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.gui.StructureViewer.ViewerType; -import jalview.io.AppletFormatAdapter; import jalview.io.JalviewFileChooser; import jalview.io.JalviewFileView; import jalview.schemes.BuriedColourScheme; @@ -59,6 +58,8 @@ import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; import java.util.Vector; import javax.swing.JCheckBoxMenuItem; @@ -84,8 +85,6 @@ public class AppJmol extends StructureViewerBase RenderPanel renderPanel; - private boolean addingStructures = false; - ViewSelectionMenu seqColourBy; /** @@ -251,98 +250,39 @@ public class AppJmol extends StructureViewerBase final AlignmentPanel ap) { progressBar = ap.alignFrame; - // //////////////////////////////// - // Is the pdb file already loaded? - String alreadyMapped = ap.getStructureSelectionManager() - .alreadyMappedToFile(pdbentry.getId()); + String pdbId = pdbentry.getId(); - if (alreadyMapped != null) + /* + * If the PDB file is already loaded, the user may just choose to add to an + * existing viewer (or cancel) + */ + if (addAlreadyLoadedFile(seq, chains, ap, pdbId)) { - int option = JOptionPane.showInternalConfirmDialog(Desktop.desktop, - MessageManager.formatMessage( - "label.pdb_entry_is_already_displayed", new String[] - { pdbentry.getId() }), MessageManager.formatMessage( - "label.map_sequences_to_visible_window", new String[] - { pdbentry.getId() }), - JOptionPane.YES_NO_CANCEL_OPTION); - - if (option == JOptionPane.CANCEL_OPTION) - { - return; - } - if (option == JOptionPane.YES_OPTION) - { - // TODO : Fix multiple seq to one chain issue here. - ap.getStructureSelectionManager().setMapping(seq, chains, - alreadyMapped, AppletFormatAdapter.FILE); - if (ap.getSeqPanel().seqCanvas.fr != null) - { - ap.getSeqPanel().seqCanvas.fr.featuresAdded(); - ap.paintAlignment(true); - } - - // Now this AppJmol is mapped to new sequences. We must add them to - // the exisiting array - JInternalFrame[] frames = Desktop.instance.getAllFrames(); - - for (int i = 0; i < frames.length; i++) - { - if (frames[i] instanceof AppJmol) - { - final AppJmol topJmol = ((AppJmol) frames[i]); - // JBPNOTE: this looks like a binding routine, rather than a gui - // routine - for (int pe = 0; pe < topJmol.jmb.getPdbCount(); pe++) - { - if (topJmol.jmb.getPdbEntry(pe).getFile() - .equals(alreadyMapped)) - { - topJmol.jmb.addSequence(pe, seq); - topJmol.addAlignmentPanel(ap); - // add it to the set used for colouring - topJmol.useAlignmentPanelForColourbyseq(ap); - topJmol.buildActionMenu(); - ap.getStructureSelectionManager() - .sequenceColoursChanged(ap); - break; - } - } - } - } - - return; - } + return; } /* * Check if there are other Jmol views involving this alignment and prompt * user about adding this molecule to one of them */ - for (AppJmol topJmol : getJmolsFor(ap)) + if (addToExistingViewer(pdbentry, seq, chains, ap, pdbId)) { - // TODO: highlight topJmol in view somehow - int option = JOptionPane.showInternalConfirmDialog(Desktop.desktop, - MessageManager.formatMessage("label.add_pdbentry_to_view", - new String[] - { pdbentry.getId(), topJmol.getTitle() }), - MessageManager - .getString("label.align_to_existing_structure_view"), - JOptionPane.YES_NO_CANCEL_OPTION); - if (option == JOptionPane.CANCEL_OPTION) - { - return; - } - if (option == JOptionPane.YES_OPTION) - { - topJmol.useAlignmentPanelForSuperposition(ap); - topJmol.addStructure(pdbentry, seq, chains, true, ap.alignFrame); - return; - } + return; } - // ///////////////////////////////// - openNewJmol(ap, new PDBEntry[] - { pdbentry }, new SequenceI[][] - { seq }); + + /* + * If the options above are declined or do not apply, open a new viewer + */ + openNewJmol(ap, new PDBEntry[] { pdbentry }, new SequenceI[][] { seq }); + } + + /** + * Answers true if this viewer already involves the given PDB ID + */ + @Override + protected boolean hasPdbId(String pdbId) + { + return jmb.hasPdbId(pdbId); } private void openNewJmol(AlignmentPanel ap, PDBEntry[] pdbentrys, @@ -392,78 +332,23 @@ public class AppJmol extends StructureViewerBase } /** - * pdb retrieval thread. + * Returns a list of any Jmol viewers. The list is restricted to those linked + * to the given alignment panel if it is not null. */ - private Thread worker = null; - - /** - * add a new structure (with associated sequences and chains) to this viewer, - * retrieving it if necessary first. - * - * @param pdbentry - * @param seq - * @param chains - * @param alignFrame - * @param align - * if true, new structure(s) will be align using associated alignment - */ - private void addStructure(final PDBEntry pdbentry, final SequenceI[] seq, - final String[] chains, final boolean b, - final IProgressIndicator alignFrame) - { - if (pdbentry.getFile() == null) - { - if (worker != null && worker.isAlive()) - { - // a retrieval is in progress, wait around and add ourselves to the - // queue. - new Thread(new Runnable() - { - public void run() - { - while (worker != null && worker.isAlive() && _started) - { - try - { - Thread.sleep(100 + ((int) Math.random() * 100)); - - } catch (Exception e) - { - } - - } - // and call ourselves again. - addStructure(pdbentry, seq, chains, b, alignFrame); - } - }).start(); - return; - } - } - // otherwise, start adding the structure. - jmb.addSequenceAndChain(new PDBEntry[] - { pdbentry }, new SequenceI[][] - { seq }, new String[][] - { chains }); - addingStructures = true; - _started = false; - alignAddedStructures = b; - progressBar = alignFrame; // visual indication happens on caller frame. - (worker = new Thread(this)).start(); - return; - } - - private Vector getJmolsFor(AlignmentPanel apanel) + @Override + protected List getViewersFor(AlignmentPanel apanel) { - Vector result = new Vector(); + List result = new ArrayList(); JInternalFrame[] frames = Desktop.instance.getAllFrames(); for (JInternalFrame frame : frames) { if (frame instanceof AppJmol) { - if (((AppJmol) frame).isLinkedWith(apanel)) + if (apanel == null + || ((StructureViewerBase) frame).isLinkedWith(apanel)) { - result.addElement((AppJmol) frame); + result.add((StructureViewerBase) frame); } } } @@ -547,8 +432,6 @@ public class AppJmol extends StructureViewerBase boolean allChainsSelected = false; - private boolean alignAddedStructures = false; - void centerViewer() { Vector toshow = new Vector(); @@ -568,8 +451,11 @@ public class AppJmol extends StructureViewerBase public void closeViewer(boolean closeExternalViewer) { - // JMol does not use an external viewer - jmb.closeViewer(); + // Jmol does not use an external viewer + if (jmb != null) + { + jmb.closeViewer(); + } setAlignmentPanel(null); _aps.clear(); _alignwith.clear(); @@ -579,11 +465,6 @@ public class AppJmol extends StructureViewerBase jmb = null; } - /** - * state flag for PDB retrieval thread - */ - private boolean _started = false; - public void run() { _started = true; @@ -1228,4 +1109,10 @@ public class AppJmol extends StructureViewerBase return ViewerType.JMOL; } + @Override + protected AAStructureBindingModel getBindingModel() + { + return jmb; + } + } diff --git a/src/jalview/gui/ChimeraViewFrame.java b/src/jalview/gui/ChimeraViewFrame.java index 1d60d6c..72c5054 100644 --- a/src/jalview/gui/ChimeraViewFrame.java +++ b/src/jalview/gui/ChimeraViewFrame.java @@ -20,6 +20,31 @@ */ package jalview.gui; +import jalview.bin.Cache; +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.ColumnSelection; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.SequenceI; +import jalview.ext.rbvi.chimera.JalviewChimeraBinding; +import jalview.gui.StructureViewer.ViewerType; +import jalview.io.AppletFormatAdapter; +import jalview.io.JalviewFileChooser; +import jalview.io.JalviewFileView; +import jalview.schemes.BuriedColourScheme; +import jalview.schemes.ColourSchemeI; +import jalview.schemes.HelixColourScheme; +import jalview.schemes.HydrophobicColourScheme; +import jalview.schemes.PurinePyrimidineColourScheme; +import jalview.schemes.StrandColourScheme; +import jalview.schemes.TaylorColourScheme; +import jalview.schemes.TurnColourScheme; +import jalview.schemes.ZappoColourScheme; +import jalview.structures.models.AAStructureBindingModel; +import jalview.util.MessageManager; +import jalview.util.Platform; +import jalview.ws.dbsources.Pdb; + import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; @@ -50,31 +75,6 @@ import javax.swing.event.InternalFrameEvent; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; -import jalview.bin.Cache; -import jalview.datamodel.Alignment; -import jalview.datamodel.AlignmentI; -import jalview.datamodel.ColumnSelection; -import jalview.datamodel.PDBEntry; -import jalview.datamodel.SequenceI; -import jalview.ext.rbvi.chimera.JalviewChimeraBinding; -import jalview.gui.StructureViewer.ViewerType; -import jalview.io.AppletFormatAdapter; -import jalview.io.JalviewFileChooser; -import jalview.io.JalviewFileView; -import jalview.schemes.BuriedColourScheme; -import jalview.schemes.ColourSchemeI; -import jalview.schemes.HelixColourScheme; -import jalview.schemes.HydrophobicColourScheme; -import jalview.schemes.PurinePyrimidineColourScheme; -import jalview.schemes.StrandColourScheme; -import jalview.schemes.TaylorColourScheme; -import jalview.schemes.TurnColourScheme; -import jalview.schemes.ZappoColourScheme; -import jalview.structures.models.AAStructureBindingModel; -import jalview.util.MessageManager; -import jalview.util.Platform; -import jalview.ws.dbsources.Pdb; - /** * GUI elements for handling an external chimera display * @@ -87,23 +87,9 @@ public class ChimeraViewFrame extends StructureViewerBase private boolean allChainsSelected = false; - private boolean alignAddedStructures = false; - - /* - * state flag for PDB retrieval thread - */ - private boolean _started = false; - - private boolean addingStructures = false; - private IProgressIndicator progressBar = null; /* - * pdb retrieval thread. - */ - private Thread worker = null; - - /* * Path to Chimera session file. This is set when an open Jalview/Chimera * session is saved, or on restore from a Jalview project (if it holds the * filename of any saved Chimera sessions). @@ -211,158 +197,32 @@ public class ChimeraViewFrame extends StructureViewerBase String[] chains, final AlignmentPanel ap) { super(); - - /* - * is the pdb file already loaded? - */ String pdbId = pdbentry.getId(); - String alreadyMapped = ap.getStructureSelectionManager() - .alreadyMappedToFile(pdbId); - - if (alreadyMapped != null) - { - int option = chooseAddSequencesToViewer(pdbId); - if (option == JOptionPane.CANCEL_OPTION) - { - return; - } - if (option == JOptionPane.YES_OPTION) - { - addSequenceMappingsToStructure(seq, chains, ap, alreadyMapped); - return; - } - } /* - * Check if there are other Chimera views involving this alignment and give - * user the option to add and align this molecule to one of them + * If the PDB file is already loaded, the user may just choose to add to an + * existing viewer (or cancel) */ - List existingViews = getChimeraWindowsFor(ap); - for (ChimeraViewFrame view : existingViews) + if (addAlreadyLoadedFile(seq, chains, ap, pdbId)) { - // TODO: highlight view somehow - /* - * JAL-1742 exclude view with this structure already mapped (don't offer - * to align chain B to chain A of the same structure) - */ - if (view.hasPdbId(pdbId)) - { - continue; - } - int option = chooseAlignStructureToViewer(pdbId, view); - if (option == JOptionPane.CANCEL_OPTION) - { - return; - } - if (option == JOptionPane.YES_OPTION) - { - view.useAlignmentPanelForSuperposition(ap); - view.addStructure(pdbentry, seq, chains, true, ap.alignFrame); - return; - } + return; } /* - * If the options above are declined or do not apply, open a new viewer - */ - openNewChimera(ap, new PDBEntry[] - { pdbentry }, new SequenceI[][] - { seq }); - } - - /** - * Presents a dialog with the option to add an align a structure to an - * existing Chimera view - * - * @param pdbId - * @param view - * @return YES, NO or CANCEL JOptionPane code - */ - protected int chooseAlignStructureToViewer(String pdbId, - ChimeraViewFrame view) - { - int option = JOptionPane.showInternalConfirmDialog(Desktop.desktop, - MessageManager.formatMessage("label.add_pdbentry_to_view", - new Object[] - { pdbId, view.getTitle() }), MessageManager - .getString("label.align_to_existing_structure_view"), - JOptionPane.YES_NO_CANCEL_OPTION); - return option; - } - - /** - * Presents a dialog with the option to add sequences to a viewer which - * already has their structure open - * - * @param pdbId - * @return YES, NO or CANCEL JOptionPane code - */ - protected int chooseAddSequencesToViewer(String pdbId) - { - int option = JOptionPane.showInternalConfirmDialog(Desktop.desktop, - MessageManager.formatMessage( - "label.pdb_entry_is_already_displayed", new Object[] - { pdbId }), MessageManager.formatMessage( - "label.map_sequences_to_visible_window", new Object[] - { pdbId }), JOptionPane.YES_NO_CANCEL_OPTION); - return option; - } - - /** - * Adds mappings for the given sequences to an already opened PDB structure, - * and updates any viewers that have the PDB file - * - * @param seq - * @param chains - * @param ap - * @param pdbFilename - */ - protected void addSequenceMappingsToStructure(SequenceI[] seq, - String[] chains, final AlignmentPanel ap, String pdbFilename) - { - // TODO : Fix multiple seq to one chain issue here. - /* - * create the mappings - */ - ap.getStructureSelectionManager().setMapping(seq, chains, pdbFilename, - AppletFormatAdapter.FILE); - - /* - * alert the FeatureRenderer to show new (PDB RESNUM) features + * Check if there are other Chimera views involving this alignment and give + * user the option to add and align this molecule to one of them (or cancel) */ - if (ap.getSeqPanel().seqCanvas.fr != null) + if (addToExistingViewer(pdbentry, seq, chains, ap, pdbId)) { - ap.getSeqPanel().seqCanvas.fr.featuresAdded(); - ap.paintAlignment(true); + return; } /* - * add the sequences to any other Chimera viewers for this pdb file + * If the options above are declined or do not apply, show the structure in + * a new viewer */ - // JBPNOTE: this looks like a binding routine, rather than a gui routine - for (JInternalFrame frame : Desktop.instance.getAllFrames()) - { - if (frame instanceof ChimeraViewFrame) - { - ChimeraViewFrame chimeraView = ((ChimeraViewFrame) frame); - for (int pe = 0; pe < chimeraView.jmb.getPdbCount(); pe++) - { - if (chimeraView.jmb.getPdbEntry(pe).getFile().equals(pdbFilename)) - { - chimeraView.jmb.addSequence(pe, seq); - chimeraView.addAlignmentPanel(ap); - /* - * add it to the set of alignments used for colouring structure by - * sequence - */ - chimeraView.useAlignmentPanelForColourbyseq(ap); - chimeraView.buildActionMenu(); - ap.getStructureSelectionManager().sequenceColoursChanged(ap); - break; - } - } - } - } + openNewChimera(ap, new PDBEntry[] { pdbentry }, + new SequenceI[][] { seq }); } /** @@ -376,6 +236,10 @@ public class ChimeraViewFrame extends StructureViewerBase } } + /** + * Answers true if this viewer already involves the given PDB ID + */ + @Override protected boolean hasPdbId(String pdbId) { return jmb.hasPdbId(pdbId); @@ -521,73 +385,22 @@ public class ChimeraViewFrame extends StructureViewerBase } /** - * add a new structure (with associated sequences and chains) to this viewer, - * retrieving it if necessary first. - * - * @param pdbentry - * @param seq - * @param chains - * @param alignFrame - * @param align - * if true, new structure(s) will be align using associated alignment + * Returns a list of any Chimera viewers in the desktop. The list is + * restricted to those linked to the given alignment panel if it is not null. */ - private void addStructure(final PDBEntry pdbentry, final SequenceI[] seq, - final String[] chains, final boolean b, - final IProgressIndicator alignFrame) - { - if (pdbentry.getFile() == null) - { - if (worker != null && worker.isAlive()) - { - // a retrieval is in progress, wait around and add ourselves to the - // queue. - new Thread(new Runnable() - { - public void run() - { - while (worker != null && worker.isAlive() && _started) - { - try - { - Thread.sleep(100 + ((int) Math.random() * 100)); - - } catch (Exception e) - { - } - - } - // and call ourselves again. - addStructure(pdbentry, seq, chains, b, alignFrame); - } - }).start(); - return; - } - } - // otherwise, start adding the structure. - jmb.addSequenceAndChain(new PDBEntry[] - { pdbentry }, new SequenceI[][] - { seq }, new String[][] - { chains }); - addingStructures = true; - _started = false; - alignAddedStructures = b; - // progressBar = alignFrame; // visual indication happens on caller frame. - (worker = new Thread(this)).start(); - return; - } - - private List getChimeraWindowsFor(AlignmentPanel apanel) + @Override + protected List getViewersFor(AlignmentPanel ap) { - List result = new ArrayList(); + List result = new ArrayList(); JInternalFrame[] frames = Desktop.instance.getAllFrames(); for (JInternalFrame frame : frames) { if (frame instanceof ChimeraViewFrame) { - if (((StructureViewerBase) frame).isLinkedWith(apanel)) + if (ap == null || ((StructureViewerBase) frame).isLinkedWith(ap)) { - result.add((ChimeraViewFrame) frame); + result.add((StructureViewerBase) frame); } } } @@ -713,7 +526,7 @@ public class ChimeraViewFrame extends StructureViewerBase */ public void closeViewer(boolean closeChimera) { - if (jmb.isChimeraRunning()) + if (jmb != null && jmb.isChimeraRunning()) { if (!closeChimera) { @@ -1395,4 +1208,10 @@ public class ChimeraViewFrame extends StructureViewerBase { return ViewerType.CHIMERA; } + + @Override + protected AAStructureBindingModel getBindingModel() + { + return jmb; + } } diff --git a/src/jalview/gui/StructureViewerBase.java b/src/jalview/gui/StructureViewerBase.java index 1feaa7c..587e08a 100644 --- a/src/jalview/gui/StructureViewerBase.java +++ b/src/jalview/gui/StructureViewerBase.java @@ -1,15 +1,21 @@ package jalview.gui; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.SequenceI; +import jalview.gui.StructureViewer.ViewerType; +import jalview.gui.ViewSelectionMenu.ViewSetProvider; +import jalview.io.AppletFormatAdapter; +import jalview.jbgui.GStructureViewer; +import jalview.structures.models.AAStructureBindingModel; +import jalview.util.MessageManager; + import java.awt.Component; import java.util.ArrayList; import java.util.List; import java.util.Vector; import javax.swing.JMenuItem; - -import jalview.gui.StructureViewer.ViewerType; -import jalview.gui.ViewSelectionMenu.ViewSetProvider; -import jalview.jbgui.GStructureViewer; +import javax.swing.JOptionPane; /** * Base class with common functionality for JMol, Chimera or other structure @@ -37,6 +43,10 @@ public abstract class StructureViewerBase extends GStructureViewer protected Vector _colourwith = new Vector(); private String viewId = null; private AlignmentPanel ap; + protected boolean alignAddedStructures = false; + protected boolean _started = false; + protected boolean addingStructures = false; + protected Thread worker = null; /** * @@ -225,4 +235,227 @@ public abstract class StructureViewerBase extends GStructureViewer } public abstract ViewerType getViewerType(); + + protected abstract AAStructureBindingModel getBindingModel(); + + /** + * add a new structure (with associated sequences and chains) to this viewer, + * retrieving it if necessary first. + * + * @param pdbentry + * @param seqs + * @param chains + * @param align + * if true, new structure(s) will be aligned using associated + * alignment + * @param alignFrame + */ + protected void addStructure(final PDBEntry pdbentry, final SequenceI[] seqs, final String[] chains, + final boolean align, final IProgressIndicator alignFrame) + { + if (pdbentry.getFile() == null) + { + if (worker != null && worker.isAlive()) + { + // a retrieval is in progress, wait around and add ourselves to the + // queue. + new Thread(new Runnable() + { + public void run() + { + while (worker != null && worker.isAlive() && _started) + { + try + { + Thread.sleep(100 + ((int) Math.random() * 100)); + + } catch (Exception e) + { + } + } + // and call ourselves again. + addStructure(pdbentry, seqs, chains, align, alignFrame); + } + }).start(); + return; + } + } + // otherwise, start adding the structure. + getBindingModel().addSequenceAndChain(new PDBEntry[] { pdbentry }, + new SequenceI[][] { seqs }, new String[][] { chains }); + addingStructures = true; + _started = false; + alignAddedStructures = align; + worker = new Thread(this); + worker.start(); + return; + } + + /** + * Presents a dialog with the option to add an align a structure to an + * existing structure view + * + * @param pdbId + * @param view + * @return YES, NO or CANCEL JOptionPane code + */ + protected int chooseAlignStructureToViewer(String pdbId, StructureViewerBase view) + { + int option = JOptionPane.showInternalConfirmDialog(Desktop.desktop, + MessageManager.formatMessage("label.add_pdbentry_to_view", + new Object[] + { pdbId, view.getTitle() }), MessageManager + .getString("label.align_to_existing_structure_view"), + JOptionPane.YES_NO_CANCEL_OPTION); + return option; + } + + protected abstract boolean hasPdbId(String pdbId); + + protected abstract List getViewersFor( + AlignmentPanel alp); + + /** + * Check for any existing views involving this alignment and give user the + * option to add and align this molecule to one of them + * + * @param pdbentry + * @param seq + * @param chains + * @param apanel + * @param pdbId + * @return true if user adds to a view, or cancels entirely, else false + */ + protected boolean addToExistingViewer(PDBEntry pdbentry, SequenceI[] seq, + String[] chains, final AlignmentPanel apanel, String pdbId) + { + for (StructureViewerBase view : getViewersFor(apanel)) + { + // TODO: highlight the view somehow + /* + * JAL-1742 exclude view with this structure already mapped (don't offer + * to align chain B to chain A of the same structure) + */ + if (view.hasPdbId(pdbId)) + { + continue; + } + int option = chooseAlignStructureToViewer(pdbId, view); + if (option == JOptionPane.CANCEL_OPTION) + { + return true; + } + else if (option == JOptionPane.YES_OPTION) + { + view.useAlignmentPanelForSuperposition(apanel); + view.addStructure(pdbentry, seq, chains, true, apanel.alignFrame); + return true; + } + else + { + // NO_OPTION - offer the next viewer if any + } + } + + /* + * nothing offered and selected + */ + return false; + } + + /** + * Adds mappings for the given sequences to an already opened PDB structure, + * and updates any viewers that have the PDB file + * + * @param seq + * @param chains + * @param apanel + * @param pdbFilename + */ + protected void addSequenceMappingsToStructure(SequenceI[] seq, + String[] chains, final AlignmentPanel apanel, String pdbFilename) + { + // TODO : Fix multiple seq to one chain issue here. + /* + * create the mappings + */ + apanel.getStructureSelectionManager().setMapping(seq, chains, pdbFilename, + AppletFormatAdapter.FILE); + + /* + * alert the FeatureRenderer to show new (PDB RESNUM) features + */ + if (apanel.getSeqPanel().seqCanvas.fr != null) + { + apanel.getSeqPanel().seqCanvas.fr.featuresAdded(); + apanel.paintAlignment(true); + } + + /* + * add the sequences to any other viewers (of the same type) for this pdb + * file + */ + // JBPNOTE: this looks like a binding routine, rather than a gui routine + for (StructureViewerBase viewer : getViewersFor(null)) + { + AAStructureBindingModel bindingModel = viewer.getBindingModel(); + for (int pe = 0; pe < bindingModel.getPdbCount(); pe++) + { + if (bindingModel.getPdbEntry(pe).getFile().equals(pdbFilename)) + { + bindingModel.addSequence(pe, seq); + viewer.addAlignmentPanel(apanel); + /* + * add it to the set of alignments used for colouring structure by + * sequence + */ + viewer.useAlignmentPanelForColourbyseq(apanel); + viewer.buildActionMenu(); + apanel.getStructureSelectionManager().sequenceColoursChanged(apanel); + break; + } + } + } + } + + /** + * Check if the PDB file is already loaded, if so offer to add it to the + * existing viewer + * + * @param seq + * @param chains + * @param apanel + * @param pdbId + * @return true if the user chooses to add to a viewer, or to cancel entirely + */ + protected boolean addAlreadyLoadedFile(SequenceI[] seq, String[] chains, + final AlignmentPanel apanel, String pdbId) + { + boolean finished = false; + String alreadyMapped = apanel.getStructureSelectionManager() + .alreadyMappedToFile(pdbId); + + if (alreadyMapped != null) + { + /* + * the PDB file is already loaded + */ + int option = JOptionPane.showInternalConfirmDialog(Desktop.desktop, + MessageManager.formatMessage( + "label.pdb_entry_is_already_displayed", new Object[] + { pdbId }), MessageManager.formatMessage( + "label.map_sequences_to_visible_window", new Object[] + { pdbId }), JOptionPane.YES_NO_CANCEL_OPTION); + if (option == JOptionPane.CANCEL_OPTION) + { + finished = true; + } + else if (option == JOptionPane.YES_OPTION) + { + addSequenceMappingsToStructure(seq, chains, apanel, alreadyMapped); + finished = true; + } + } + return finished; + } } diff --git a/src/jalview/structures/models/AAStructureBindingModel.java b/src/jalview/structures/models/AAStructureBindingModel.java index e77a23c..b844b52 100644 --- a/src/jalview/structures/models/AAStructureBindingModel.java +++ b/src/jalview/structures/models/AAStructureBindingModel.java @@ -52,6 +52,8 @@ public abstract class AAStructureBindingModel extends private boolean nucleotide; + private boolean finishedInit = false; + /** * Data bean class to simplify parameterisation in superposeStructures */ @@ -623,4 +625,14 @@ public abstract class AAStructureBindingModel extends } return false; } + + public boolean isFinishedInit() + { + return finishedInit; + } + + public void setFinishedInit(boolean fi) + { + this.finishedInit = fi; + } } \ No newline at end of file diff --git a/test/jalview/ext/rbvi/chimera/JalviewChimeraView.java b/test/jalview/ext/rbvi/chimera/JalviewChimeraView.java index 4bfabb3..b9cab9c 100644 --- a/test/jalview/ext/rbvi/chimera/JalviewChimeraView.java +++ b/test/jalview/ext/rbvi/chimera/JalviewChimeraView.java @@ -1,10 +1,13 @@ package jalview.ext.rbvi.chimera; +import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; import jalview.api.structures.JalviewStructureDisplayI; +import jalview.bin.Cache; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; +import jalview.gui.Preferences; import jalview.gui.StructureViewer; import jalview.gui.StructureViewer.ViewerType; import jalview.io.FormatAdapter; @@ -32,19 +35,13 @@ public class JalviewChimeraView @AfterClass public static void tearDownAfterClass() throws Exception { - try - { jalview.gui.Desktop.instance.closeAll_actionPerformed(null); - } catch (Exception e) - { - // ignore NullPointerException thrown by JMol - } - } @Test(groups ={ "Functional" }) public void testSingleSeqViewJMol() { + Cache.setProperty(Preferences.STRUCTURE_DISPLAY, ViewerType.JMOL.name()); String inFile = "examples/1gaq.txt"; AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded( inFile, FormatAdapter.FILE); @@ -68,11 +65,14 @@ public class JalviewChimeraView new SequenceI[] { sq }, af.getCurrentView().getAlignPanel()); /* - * Wait for viewer thread to start + * Wait for viewer load thread to complete */ try { - Thread.sleep(1000); + while (!jmolViewer.getBinding().isFinishedInit()) + { + Thread.sleep(500); + } } catch (InterruptedException e) { } @@ -89,12 +89,15 @@ public class JalviewChimeraView @Test(groups ={ "Functional" }) public void testSingleSeqViewChimera() { + Cache.setProperty(Preferences.STRUCTURE_DISPLAY, + ViewerType.CHIMERA.name()); String inFile = "examples/1gaq.txt"; AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded( inFile, FormatAdapter.FILE); assertTrue("Didn't read input file " + inFile, af != null); for (SequenceI sq : af.getViewport().getAlignment().getSequences()) { + System.out.println("** sq=" + sq.getName()); SequenceI dsq = sq.getDatasetSequence(); while (dsq.getDatasetSequence() != null) { @@ -112,14 +115,18 @@ public class JalviewChimeraView new SequenceI[] { sq }, af.getCurrentView().getAlignPanel()); /* - * Wait for viewer thread to start + * Wait for viewer load thread to complete */ - try - { - Thread.sleep(1000); - } catch (InterruptedException e) + while (!chimeraViewer.getBinding().isFinishedInit()) { + try + { + Thread.sleep(500); + } catch (InterruptedException e) + { + } } + assertEquals(1, chimeraViewer.getBinding().getPdbCount()); chimeraViewer.closeViewer(true); // todo: break here means only once through this loop? break; diff --git a/test/jalview/structures/models/AAStructureBindingModelTest.java b/test/jalview/structures/models/AAStructureBindingModelTest.java index 3354e38..1466760 100644 --- a/test/jalview/structures/models/AAStructureBindingModelTest.java +++ b/test/jalview/structures/models/AAStructureBindingModelTest.java @@ -116,7 +116,7 @@ public class AAStructureBindingModelTest } /** - * Verify that the method determines that columns 2, 5 and 6 of the aligment + * Verify that the method determines that columns 2, 5 and 6 of the alignment * are alignable in structure */ @Test(groups ={ "Functional" }) -- 1.7.10.2