package jalview.gui; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; import java.util.List; import javax.swing.JInternalFrame; import javax.swing.JMenuItem; import javax.swing.event.InternalFrameAdapter; import javax.swing.event.InternalFrameEvent; import jalview.api.AlignmentViewPanel; import jalview.api.FeatureRenderer; import jalview.bin.Cache; import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.gui.StructureViewer.ViewerType; import jalview.io.DataSourceType; import jalview.io.StructureFile; import jalview.structures.models.AAStructureBindingModel; import jalview.util.MessageManager; public class PymolViewer extends StructureViewerBase { private static final int myWidth = 500; private static final int myHeight = 150; private PymolBindingModel binding; private String pymolSessionFile; public PymolViewer() { super(); /* * closeViewer will decide whether or not to close this frame * depending on whether user chooses to Cancel or not */ setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE); } public PymolViewer(PDBEntry pdb, SequenceI[] seqs, Object object, AlignmentPanel ap) { this(); openNewPymol(ap, new PDBEntry[] { pdb }, new SequenceI[][] { seqs }); } public PymolViewer(PDBEntry[] pe, boolean alignAdded, SequenceI[][] seqs, AlignmentPanel ap) { this(); setAlignAddedStructures(alignAdded); openNewPymol(ap, pe, seqs); } /** * Constructor given a session file to be restored * * @param sessionFile * @param alignPanel * @param pdbArray * @param seqsArray * @param colourByPymol * @param colourBySequence * @param newViewId */ public PymolViewer(String sessionFile, AlignmentPanel alignPanel, PDBEntry[] pdbArray, SequenceI[][] seqsArray, boolean colourByPymol, boolean colourBySequence, String newViewId) { // TODO convert to base/factory class method this(); setViewId(newViewId); this.pymolSessionFile = sessionFile; openNewPymol(alignPanel, pdbArray, seqsArray); if (colourByPymol) { binding.setColourBySequence(false); seqColour.setSelected(false); viewerColour.setSelected(true); } else if (colourBySequence) { binding.setColourBySequence(true); seqColour.setSelected(true); viewerColour.setSelected(false); } } private void openNewPymol(AlignmentPanel ap, PDBEntry[] pe, SequenceI[][] seqs) { createProgressBar(); binding = new PymolBindingModel(this, ap.getStructureSelectionManager(), pe, seqs); addAlignmentPanel(ap); useAlignmentPanelForColourbyseq(ap); if (pe.length > 1) { useAlignmentPanelForSuperposition(ap); } binding.setColourBySequence(true); setSize(myWidth, myHeight); initMenus(); viewerActionMenu.setText("PyMOL"); updateTitleAndMenus(); addingStructures = false; worker = new Thread(this); worker.start(); this.addInternalFrameListener(new InternalFrameAdapter() { @Override public void internalFrameClosing( InternalFrameEvent internalFrameEvent) { closeViewer(false); } }); } /** * Create a helper to manage progress bar display */ protected void createProgressBar() { if (getProgressIndicator() == null) { setProgressIndicator(new ProgressBar(statusPanel, statusBar)); } } @Override public void run() { // todo pull up much of this StringBuilder errormsgs = new StringBuilder(128); List filePDB = new ArrayList<>(); List filePDBpos = new ArrayList<>(); String[] curfiles = binding.getStructureFiles(); // files currently in viewer for (int pi = 0; pi < binding.getPdbCount(); pi++) { String file = null; PDBEntry thePdbEntry = binding.getPdbEntry(pi); if (thePdbEntry.getFile() == null) { /* * Retrieve PDB data, save to file, attach to PDBEntry */ file = fetchPdbFile(thePdbEntry); if (file == null) { errormsgs.append("'" + thePdbEntry.getId() + "' "); } } else { /* * got file already */ file = new File(thePdbEntry.getFile()).getAbsoluteFile() .getPath(); // todo - skip if already loaded in PyMOL } if (file != null) { filePDB.add(thePdbEntry); filePDBpos.add(Integer.valueOf(pi)); } } if (!filePDB.isEmpty()) { /* * at least one structure to add to viewer */ binding.setFinishedInit(false); if (!addingStructures) { try { initPymol(); } catch (Exception ex) { Cache.log.error("Couldn't open PyMOL viewer!", ex); } } int num = -1; for (PDBEntry pe : filePDB) { num++; if (pe.getFile() != null) { try { int pos = filePDBpos.get(num).intValue(); long startTime = startProgressBar(getViewerName() + " " + MessageManager.getString("status.opening_file_for") + " " + pe.getId()); binding.openFile(pe); binding.addSequence(pos, binding.getSequence()[pos]); File fl = new File(pe.getFile()); DataSourceType protocol = DataSourceType.URL; try { if (fl.exists()) { protocol = DataSourceType.FILE; } } catch (Throwable e) { } finally { stopProgressBar("", startTime); } StructureFile pdb = binding.getSsm().setMapping( binding.getSequence()[pos], binding.getChains()[pos], pe.getFile(), protocol, getProgressIndicator()); binding.stashFoundChains(pdb, pe.getFile()); } catch (Exception ex) { Cache.log.error( "Couldn't open " + pe.getFile() + " in Chimera viewer!", ex); } finally { // Cache.log.debug("File locations are " + files); } } } binding.refreshGUI(); binding.setFinishedInit(true); binding.setLoadingFromArchive(false); /* * ensure that any newly discovered features (e.g. RESNUM) * are added to any open feature settings dialog */ FeatureRenderer fr = getBinding().getFeatureRenderer(null); if (fr != null) { fr.featuresAdded(); } // refresh the sequence colours for the new structure(s) for (AlignmentViewPanel ap : _colourwith) { binding.updateColours(ap); } // do superposition if asked to if (alignAddedStructures) { new Thread(new Runnable() { @Override public void run() { alignStructsWithAllAlignPanels(); } }).start(); } addingStructures = false; } _started = false; worker = null; } /** * Launch PyMOL. If we have a session file name, send PyMOL the command to * open its saved session file. */ void initPymol() { Desktop.addInternalFrame(this, binding.getViewerTitle(getViewerName(), true), getBounds().width, getBounds().height); if (!binding.launchPymol()) { JvOptionPane.showMessageDialog(Desktop.desktop, MessageManager.formatMessage("label.open_viewer_failed", getViewerName()), MessageManager.getString("label.error_loading_file"), JvOptionPane.ERROR_MESSAGE); this.dispose(); return; } if (this.pymolSessionFile != null) { boolean opened = binding.openSession(pymolSessionFile); if (!opened) { System.err.println("An error occurred opening PyMOL session file " + pymolSessionFile); } } // binding.startPymolListener(); } @Override public AAStructureBindingModel getBinding() { return binding; } @Override public ViewerType getViewerType() { return ViewerType.PYMOL; } @Override protected String getViewerName() { return "PyMOL"; } @Override protected void initMenus() { super.initMenus(); savemenu.setVisible(false); // not yet implemented viewMenu.add(fitToWindow); JMenuItem writeFeatures = new JMenuItem( MessageManager.getString("label.create_viewer_attributes")); writeFeatures.setToolTipText(MessageManager .getString("label.create_viewer_attributes_tip")); writeFeatures.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { sendFeaturesToPymol(); } }); viewerActionMenu.add(writeFeatures); } protected void sendFeaturesToPymol() { int count = binding.sendFeaturesToViewer(getAlignmentPanel()); statusBar.setText( MessageManager.formatMessage("label.attributes_set", count)); } }