X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FStructureViewerBase.java;h=f5d350c3c0fbb4bf50c0da478b87addcfda121f6;hb=f2c4dcbf716ebf695ffe757c59185bbcb4e6e2ad;hp=418a84d87b7f0e3d49bd1e9a8c99c1dde34c3a60;hpb=3da878124135ff033f42d19d8733891b09e953cd;p=jalview.git diff --git a/src/jalview/gui/StructureViewerBase.java b/src/jalview/gui/StructureViewerBase.java index 418a84d..f5d350c 100644 --- a/src/jalview/gui/StructureViewerBase.java +++ b/src/jalview/gui/StructureViewerBase.java @@ -20,26 +20,6 @@ */ package jalview.gui; -import jalview.api.AlignmentViewPanel; -import jalview.bin.Cache; -import jalview.datamodel.Alignment; -import jalview.datamodel.AlignmentI; -import jalview.datamodel.HiddenColumns; -import jalview.datamodel.PDBEntry; -import jalview.datamodel.SequenceI; -import jalview.gui.JalviewColourChooser.ColourChooserListener; -import jalview.gui.StructureViewer.ViewerType; -import jalview.gui.ViewSelectionMenu.ViewSetProvider; -import jalview.io.DataSourceType; -import jalview.io.JalviewFileChooser; -import jalview.io.JalviewFileView; -import jalview.jbgui.GStructureViewer; -import jalview.schemes.ColourSchemeI; -import jalview.schemes.ColourSchemes; -import jalview.structure.StructureMapping; -import jalview.structures.models.AAStructureBindingModel; -import jalview.util.MessageManager; - import java.awt.Color; import java.awt.Component; import java.awt.event.ActionEvent; @@ -54,6 +34,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.Random; import java.util.Vector; import javax.swing.ButtonGroup; @@ -64,6 +45,28 @@ import javax.swing.JRadioButtonMenuItem; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; +import jalview.api.AlignmentViewPanel; +import jalview.bin.Cache; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.SequenceI; +import jalview.gui.JalviewColourChooser.ColourChooserListener; +import jalview.gui.StructureViewer.ViewerType; +import jalview.gui.ViewSelectionMenu.ViewSetProvider; +import jalview.io.DataSourceType; +import jalview.io.JalviewFileChooser; +import jalview.io.JalviewFileView; +import jalview.jbgui.GStructureViewer; +import jalview.schemes.ColourSchemeI; +import jalview.schemes.ColourSchemes; +import jalview.structure.StructureMapping; +import jalview.structures.models.AAStructureBindingModel; +import jalview.util.BrowserLauncher; +import jalview.util.MessageManager; +import jalview.ws.dbsources.EBIAlfaFold; +import jalview.ws.dbsources.Pdb; +import jalview.ws.utils.UrlDownloadClient; + /** * Base class with common functionality for JMol, Chimera or other structure * viewers. @@ -90,13 +93,13 @@ public abstract class StructureViewerBase extends GStructureViewer /** * list of alignment panels to use for superposition */ - protected Vector _alignwith = new Vector<>(); + protected Vector _alignwith = new Vector<>(); /** * list of alignment panels that are used for colouring structures by aligned * sequences */ - protected Vector _colourwith = new Vector<>(); + protected Vector _colourwith = new Vector<>(); private String viewId = null; @@ -121,6 +124,10 @@ public abstract class StructureViewerBase extends GStructureViewer */ protected volatile boolean seqColoursApplied = false; + private IProgressIndicator progressBar = null; + + private Random random = new Random(); + /** * Default constructor */ @@ -148,6 +155,15 @@ public abstract class StructureViewerBase extends GStructureViewer { alignAddedStructures = alignAdded; } + + /** + * called by the binding model to indicate when adding structures is happening or has been completed + * @param addingStructures + */ + public synchronized void setAddingStructures(boolean addingStructures) + { + this.addingStructures = addingStructures; + } /** * @@ -159,13 +175,14 @@ public abstract class StructureViewerBase extends GStructureViewer return _aps.contains(ap2.av.getSequenceSetId()); } - public boolean isUsedforaligment(AlignmentPanel ap2) + public boolean isUsedforaligment(AlignmentViewPanel ap2) { return (_alignwith != null) && _alignwith.contains(ap2); } - public boolean isUsedforcolourby(AlignmentPanel ap2) + @Override + public boolean isUsedForColourBy(AlignmentViewPanel ap2) { return (_colourwith != null) && _colourwith.contains(ap2); } @@ -193,8 +210,6 @@ public abstract class StructureViewerBase extends GStructureViewer this.viewId = viewId; } - public abstract String getStateInfo(); - protected void buildActionMenu() { if (_alignwith == null) @@ -215,6 +230,7 @@ public abstract class StructureViewerBase extends GStructureViewer } } + @Override public AlignmentPanel getAlignmentPanel() { return ap; @@ -267,7 +283,8 @@ public abstract class StructureViewerBase extends GStructureViewer * * @param nap */ - public void removeAlignmentPanel(AlignmentPanel nap) + @Override + public void removeAlignmentPanel(AlignmentViewPanel nap) { try { @@ -339,8 +356,6 @@ public abstract class StructureViewerBase extends GStructureViewer public abstract ViewerType getViewerType(); - protected abstract IProgressIndicator getIProgressIndicator(); - /** * add a new structure (with associated sequences and chains) to this viewer, * retrieving it if necessary first. @@ -449,7 +464,7 @@ public abstract class StructureViewerBase extends GStructureViewer * create the mappings */ apanel.getStructureSelectionManager().setMapping(seq, chains, - pdbFilename, DataSourceType.FILE, getIProgressIndicator()); + pdbFilename, DataSourceType.FILE, getProgressIndicator()); /* * alert the FeatureRenderer to show new (PDB RESNUM) features @@ -554,8 +569,6 @@ public abstract class StructureViewerBase extends GStructureViewer } } - abstract void showSelectedChains(); - /** * Action on selecting one of Jalview's registered colour schemes */ @@ -566,7 +579,7 @@ public abstract class StructureViewerBase extends GStructureViewer ColourSchemeI cs = ColourSchemes.getInstance() .getColourScheme(colourSchemeName, getAlignmentPanel().av, al, null); - getBinding().setJalviewColourScheme(cs); + getBinding().colourByJalviewColourScheme(cs); } /** @@ -600,7 +613,7 @@ public abstract class StructureViewerBase extends GStructureViewer @Override public void actionPerformed(ActionEvent actionEvent) { - viewerColour_actionPerformed(actionEvent); + viewerColour_actionPerformed(); } }); colourMenu.add(viewerColour); @@ -616,7 +629,7 @@ public abstract class StructureViewerBase extends GStructureViewer @Override public void actionPerformed(ActionEvent actionEvent) { - background_actionPerformed(actionEvent); + background_actionPerformed(); } }); colourMenu.add(backGround); @@ -647,7 +660,7 @@ public abstract class StructureViewerBase extends GStructureViewer @Override public void actionPerformed(ActionEvent actionEvent) { - seqColour_actionPerformed(actionEvent); + seqColour_actionPerformed(); } }); @@ -659,7 +672,7 @@ public abstract class StructureViewerBase extends GStructureViewer @Override public void actionPerformed(ActionEvent actionEvent) { - chainColour_actionPerformed(actionEvent); + chainColour_actionPerformed(); } }); @@ -671,12 +684,15 @@ public abstract class StructureViewerBase extends GStructureViewer @Override public void actionPerformed(ActionEvent actionEvent) { - chargeColour_actionPerformed(actionEvent); + chargeColour_actionPerformed(); } }); viewerColour = new JRadioButtonMenuItem(); - // text is set in overrides of this method + viewerColour + .setText(MessageManager.getString("label.colour_with_viewer")); + viewerColour.setToolTipText(MessageManager + .getString("label.let_viewer_manage_structure_colours")); viewerColour.setName(ViewerColour.ByViewer.name()); viewerColour.setSelected(!binding.isColourBySequence()); @@ -702,8 +718,8 @@ public abstract class StructureViewerBase extends GStructureViewer } else { - // update the Chimera display now. - seqColour_actionPerformed(null); + // update the viewer display now. + seqColour_actionPerformed(); } } }); @@ -714,10 +730,18 @@ public abstract class StructureViewerBase extends GStructureViewer @Override public void itemStateChanged(ItemEvent e) { - alignStructs.setEnabled(!_alignwith.isEmpty()); - alignStructs.setToolTipText(MessageManager.formatMessage( - "label.align_structures_using_linked_alignment_views", - _alignwith.size())); + if (_alignwith.isEmpty()) + { + alignStructs.setEnabled(false); + alignStructs.setToolTipText(null); + } + else + { + alignStructs.setEnabled(true); + alignStructs.setToolTipText(MessageManager.formatMessage( + "label.align_structures_using_linked_alignment_views", + _alignwith.size())); + } } }; viewSelectionMenu = new ViewSelectionMenu( @@ -744,13 +768,11 @@ public abstract class StructureViewerBase extends GStructureViewer } }); - buildColourMenu(); - } + viewerActionMenu.setText(getViewerName()); + helpItem.setText(MessageManager.formatMessage("label.viewer_help", + getViewerName())); - @Override - public void setJalviewColourScheme(ColourSchemeI cs) - { - getBinding().setJalviewColourScheme(cs); + buildColourMenu(); } /** @@ -759,12 +781,7 @@ public abstract class StructureViewerBase extends GStructureViewer * the operation. */ @Override - protected String alignStructs_actionPerformed(ActionEvent actionEvent) - { - return alignStructs_withAllAlignPanels(); - } - - protected String alignStructs_withAllAlignPanels() + protected String alignStructsWithAllAlignPanels() { if (getAlignmentPanel() == null) { @@ -779,19 +796,8 @@ public abstract class StructureViewerBase extends GStructureViewer String reply = null; try { - AlignmentI[] als = new Alignment[_alignwith.size()]; - HiddenColumns[] alc = new HiddenColumns[_alignwith.size()]; - int[] alm = new int[_alignwith.size()]; - int a = 0; - - for (AlignmentPanel alignPanel : _alignwith) - { - als[a] = alignPanel.av.getAlignment(); - alm[a] = -1; - alc[a++] = alignPanel.av.getAlignment().getHiddenColumns(); - } - reply = getBinding().superposeStructures(als, alm, alc); - if (reply != null) + reply = getBinding().superposeStructures(_alignwith); + if (reply != null && !reply.isEmpty()) { String text = MessageManager .formatMessage("error.superposition_failed", reply); @@ -800,9 +806,9 @@ public abstract class StructureViewerBase extends GStructureViewer } catch (Exception e) { StringBuffer sp = new StringBuffer(); - for (AlignmentPanel alignPanel : _alignwith) + for (AlignmentViewPanel alignPanel : _alignwith) { - sp.append("'" + alignPanel.alignFrame.getTitle() + "' "); + sp.append("'" + alignPanel.getViewName() + "' "); } Cache.log.info("Couldn't align structures with the " + sp.toString() + "associated alignment panels.", e); @@ -815,7 +821,7 @@ public abstract class StructureViewerBase extends GStructureViewer * background of the structure viewer */ @Override - public void background_actionPerformed(ActionEvent actionEvent) + public void background_actionPerformed() { String ttl = MessageManager.getString("label.select_background_colour"); ColourChooserListener listener = new ColourChooserListener() @@ -830,7 +836,7 @@ public abstract class StructureViewerBase extends GStructureViewer } @Override - public void viewerColour_actionPerformed(ActionEvent actionEvent) + public void viewerColour_actionPerformed() { if (viewerColour.isSelected()) { @@ -840,21 +846,21 @@ public abstract class StructureViewerBase extends GStructureViewer } @Override - public void chainColour_actionPerformed(ActionEvent actionEvent) + public void chainColour_actionPerformed() { chainColour.setSelected(true); getBinding().colourByChain(); } @Override - public void chargeColour_actionPerformed(ActionEvent actionEvent) + public void chargeColour_actionPerformed() { chargeColour.setSelected(true); getBinding().colourByCharge(); } @Override - public void seqColour_actionPerformed(ActionEvent actionEvent) + public void seqColour_actionPerformed() { AAStructureBindingModel binding = getBinding(); binding.setColourBySequence(seqColour.isSelected()); @@ -873,7 +879,7 @@ public abstract class StructureViewerBase extends GStructureViewer } } // Set the colour using the current view for the associated alignframe - for (AlignmentPanel alignPanel : _colourwith) + for (AlignmentViewPanel alignPanel : _colourwith) { binding.colourBySequence(alignPanel); } @@ -882,7 +888,7 @@ public abstract class StructureViewerBase extends GStructureViewer } @Override - public void pdbFile_actionPerformed(ActionEvent actionEvent) + public void pdbFile_actionPerformed() { // TODO: JAL-3048 not needed for Jalview-JS - save PDB file JalviewFileChooser chooser = new JalviewFileChooser( @@ -934,7 +940,7 @@ public abstract class StructureViewerBase extends GStructureViewer } @Override - public void viewMapping_actionPerformed(ActionEvent actionEvent) + public void viewMapping_actionPerformed() { CutAndPasteTransfer cap = new CutAndPasteTransfer(); try @@ -975,7 +981,7 @@ public abstract class StructureViewerBase extends GStructureViewer * enable 'Superpose with' if more than one mapped structure */ viewSelectionMenu.setEnabled(false); - if (getBinding().getStructureFiles().length > 1 + if (getBinding().getMappedStructureCount() > 1 && getBinding().getSequence().length > 1) { viewSelectionMenu.setEnabled(true); @@ -996,7 +1002,7 @@ public abstract class StructureViewerBase extends GStructureViewer if (!binding.isLoadingFromArchive()) { - seqColour_actionPerformed(null); + seqColour_actionPerformed(); } } @@ -1049,4 +1055,230 @@ public abstract class StructureViewerBase extends GStructureViewer toFront(); } + @Override + public long startProgressBar(String msg) + { + // TODO would rather have startProgress/stopProgress as the + // IProgressIndicator interface + long tm = random.nextLong(); + if (progressBar != null) + { + progressBar.setProgressBar(msg, tm); + } + return tm; + } + + @Override + public void stopProgressBar(String msg, long handle) + { + if (progressBar != null) + { + progressBar.setProgressBar(msg, handle); + } + } + + protected IProgressIndicator getProgressIndicator() + { + return progressBar; + } + + protected void setProgressIndicator(IProgressIndicator pi) + { + progressBar = pi; + } + + public void setProgressMessage(String message, long id) + { + if (progressBar != null) + { + progressBar.setProgressBar(message, id); + } + } + + @Override + public void showConsole(boolean show) + { + // default does nothing + } + + /** + * Show only the selected chain(s) in the viewer + */ + protected void showSelectedChains() + { + List toshow = new ArrayList<>(); + for (int i = 0; i < chainMenu.getItemCount(); i++) + { + if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem) + { + JCheckBoxMenuItem item = (JCheckBoxMenuItem) chainMenu.getItem(i); + if (item.isSelected()) + { + toshow.add(item.getText()); + } + } + } + getBinding().showChains(toshow); + } + + /** + * Tries to fetch a PDB file and save to a temporary local file. Returns the + * saved file path if successful, or null if not. + * + * @param processingEntry + * @return + */ + protected String fetchPdbFile(PDBEntry processingEntry) + { + String filePath = null; + Pdb pdbclient = new Pdb(); + EBIAlfaFold afclient = new EBIAlfaFold(); + AlignmentI pdbseq = null; + String pdbid = processingEntry.getId(); + long handle = System.currentTimeMillis() + + Thread.currentThread().hashCode(); + + /* + * Write 'fetching PDB' progress on AlignFrame as we are not yet visible + */ + String msg = MessageManager.formatMessage("status.fetching_pdb", + new Object[] + { pdbid }); + getAlignmentPanel().alignFrame.setProgressBar(msg, handle); + // long hdl = startProgressBar(MessageManager.formatMessage( + // "status.fetching_pdb", new Object[] + // { pdbid })); + try + { + if (afclient.isValidReference(pdbid)) + { + pdbseq = afclient.getSequenceRecords(pdbid); + } else { + if (processingEntry.hasRetrievalUrl()) + { + // retrieve from URL to new local tmpfile + File tmpFile = File.createTempFile(pdbid, + "." + (PDBEntry.Type.MMCIF.toString().equals( + processingEntry.getType().toString()) ? "cif" + : "pdb")); + String fromUrl = processingEntry.getRetrievalUrl(); + UrlDownloadClient.download(fromUrl, tmpFile); + + // may not need this check ? + String file = tmpFile.getAbsolutePath(); + if (file != null) + { + pdbseq = EBIAlfaFold.importDownloadedStructureFromUrl(fromUrl,tmpFile,pdbid,null,null,null); + } + } else { + pdbseq = pdbclient.getSequenceRecords(pdbid); + } + } + } catch (Exception e) + { + System.err.println( + "Error retrieving PDB id " + pdbid + ": " + e.getMessage()); + } finally + { + msg = pdbid + " " + MessageManager.getString("label.state_completed"); + getAlignmentPanel().alignFrame.setProgressBar(msg, handle); + // stopProgressBar(msg, hdl); + } + /* + * If PDB data were saved and are not invalid (empty alignment), return the + * file path. + */ + if (pdbseq != null && pdbseq.getHeight() > 0) + { + // just use the file name from the first sequence's first PDBEntry + filePath = new File(pdbseq.getSequenceAt(0).getAllPDBEntries() + .elementAt(0).getFile()).getAbsolutePath(); + processingEntry.setFile(filePath); + } + return filePath; + } + + /** + * If supported, saves the state of the structure viewer to a temporary file + * and returns the file, else returns null + * + * @return + */ + public File saveSession() + { + // TODO: a wait loop to ensure the file is written fully before returning? + return getBinding() == null ? null : getBinding().saveSession(); + } + + /** + * Close down this instance of Jalview's Chimera viewer, giving the user the + * option to close the associated Chimera window (process). They may wish to + * keep it open until they have had an opportunity to save any work. + * + * @param forceClose + * if true, close any linked Chimera process; if false, prompt first + */ + @Override + public void closeViewer(boolean forceClose) + { + AAStructureBindingModel binding = getBinding(); + if (binding != null && binding.isViewerRunning()) + { + if (!forceClose) + { + String viewerName = getViewerName(); + String prompt = MessageManager + .formatMessage("label.confirm_close_viewer", new Object[] + { binding.getViewerTitle(viewerName, false), viewerName }); + prompt = JvSwingUtils.wrapTooltip(true, prompt); + int confirm = JvOptionPane.showConfirmDialog(this, prompt, + MessageManager.getString("label.close_viewer"), + JvOptionPane.YES_NO_CANCEL_OPTION); + /* + * abort closure if user hits escape or Cancel + */ + if (confirm == JvOptionPane.CANCEL_OPTION + || confirm == JvOptionPane.CLOSED_OPTION) + { + return; + } + forceClose = confirm == JvOptionPane.YES_OPTION; + } + } + if (binding != null) + { + binding.closeViewer(forceClose); + } + setAlignmentPanel(null); + _aps.clear(); + _alignwith.clear(); + _colourwith.clear(); + // TODO: check for memory leaks where instance isn't finalised because jmb + // holds a reference to the window + // jmb = null; + dispose(); + } + + @Override + public void showHelp_actionPerformed() + { + try + { + String url = getBinding().getHelpURL(); + if (url != null) + { + BrowserLauncher.openURL(url); + } + } catch (IOException ex) + { + System.err + .println("Show " + getViewerName() + " failed with: " + + ex.getMessage()); + } + } + @Override + public boolean hasViewerActionsMenu() + { + return viewerActionMenu!=null && viewerActionMenu.isEnabled() && viewerActionMenu.getItemCount()>0 && viewerActionMenu.isVisible(); + } }