--- /dev/null
+package jalview.gui;
+
+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;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JInternalFrame;
+import javax.swing.event.InternalFrameAdapter;
+import javax.swing.event.InternalFrameEvent;
+
+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);
+ }
+
+ 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();
+
+ 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<PDBEntry> filePDB = new ArrayList<>();
+ List<Integer> 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.getString("label.pymol_failed"),
+ 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 void closeViewer(boolean closePymol)
+ {
+ if (binding != null && binding.isPymolRunning())
+ {
+ if (!closePymol)
+ {
+ // TODO i18n (and pull up)
+ String prompt = MessageManager
+ .formatMessage("label.confirm_close_pymol", new Object[]
+ { binding.getViewerTitle(getViewerName(), false) });
+ 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;
+ }
+ closePymol = confirm == JvOptionPane.YES_OPTION;
+ }
+ binding.closeViewer(closePymol);
+ }
+ setAlignmentPanel(null);
+ _aps.clear();
+ _alignwith.clear();
+ _colourwith.clear();
+ // TODO: check for memory leaks where instance isn't finalised because
+ // binding
+ // holds a reference to the window
+ binding = null;
+ dispose();
+ }
+
+ @Override
+ public String getStateInfo()
+ {
+ return null;
+ }
+
+ @Override
+ public ViewerType getViewerType()
+ {
+ return ViewerType.PYMOL;
+ }
+
+ @Override
+ protected String getViewerName()
+ {
+ return "PyMOL";
+ }
+
+}