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 java.util.Locale;
25 import java.awt.BorderLayout;
26 import java.awt.Color;
27 import java.awt.Dimension;
29 import java.awt.Graphics;
31 import java.util.List;
34 import javax.swing.JPanel;
35 import javax.swing.JSplitPane;
36 import javax.swing.SwingUtilities;
37 import javax.swing.event.InternalFrameAdapter;
38 import javax.swing.event.InternalFrameEvent;
40 import jalview.api.AlignmentViewPanel;
41 import jalview.bin.Console;
42 import jalview.datamodel.PDBEntry;
43 import jalview.datamodel.SequenceI;
44 import jalview.datamodel.StructureViewerModel;
45 import jalview.datamodel.StructureViewerModel.StructureData;
46 import jalview.fts.service.alphafold.AlphafoldRestClient;
47 import jalview.gui.ImageExporter.ImageWriterI;
48 import jalview.gui.StructureViewer.ViewerType;
49 import jalview.structure.StructureCommand;
50 import jalview.structures.models.AAStructureBindingModel;
51 import jalview.util.BrowserLauncher;
52 import jalview.util.ImageMaker;
53 import jalview.util.MessageManager;
54 import jalview.util.Platform;
55 public class AppJmol extends StructureViewerBase
57 // ms to wait for Jmol to load files
58 private static final int JMOL_LOAD_TIMEOUT = 20000;
60 private static final String SPACE = " ";
62 private static final String QUOTE = "\"";
70 RenderPanel renderPanel;
79 * - add the alignment panel to the list used for colouring these
82 * - add the alignment panel to the list used for aligning these
84 * @param leaveColouringToJmol
85 * - do not update the colours from any other source. Jmol is
91 public AppJmol(StructureViewerModel viewerModel, AlignmentPanel ap,
92 String sessionFile, String viewid)
94 Map<File, StructureData> pdbData = viewerModel.getFileData();
95 PDBEntry[] pdbentrys = new PDBEntry[pdbData.size()];
96 SequenceI[][] seqs = new SequenceI[pdbData.size()][];
98 for (StructureData data : pdbData.values())
100 PDBEntry pdbentry = new PDBEntry(data.getPdbId(), null,
101 PDBEntry.Type.PDB, data.getFilePath());
102 pdbentrys[i] = pdbentry;
103 List<SequenceI> sequencesForPdb = data.getSeqList();
104 seqs[i] = sequencesForPdb
105 .toArray(new SequenceI[sequencesForPdb.size()]);
108 // TODO: check if protocol is needed to be set, and if chains are
110 jmb = new AppJmolBinding(this, ap.getStructureSelectionManager(),
111 pdbentrys, seqs, null);
113 jmb.setLoadingFromArchive(true);
114 addAlignmentPanel(ap);
115 if (viewerModel.isAlignWithPanel())
117 useAlignmentPanelForSuperposition(ap);
120 boolean useToColour = viewerModel.isColourWithAlignPanel();
121 boolean leaveColouringToJmol = viewerModel.isColourByViewer();
122 if (leaveColouringToJmol || !useToColour)
124 jmb.setColourBySequence(false);
125 seqColour.setSelected(false);
126 viewerColour.setSelected(true);
128 else if (useToColour)
130 useAlignmentPanelForColourbyseq(ap);
131 jmb.setColourBySequence(true);
132 seqColour.setSelected(true);
133 viewerColour.setSelected(false);
135 this.setBounds(viewerModel.getX(), viewerModel.getY(),
136 viewerModel.getWidth(), viewerModel.getHeight());
139 this.addInternalFrameListener(new InternalFrameAdapter()
142 public void internalFrameClosing(
143 InternalFrameEvent internalFrameEvent)
148 StringBuilder cmd = new StringBuilder();
149 cmd.append("load FILES ").append(QUOTE)
150 .append(Platform.escapeBackslashes(sessionFile)).append(QUOTE);
151 initJmol(cmd.toString());
155 protected void initMenus()
161 .setText(MessageManager.getString("label.colour_with_jmol"));
162 viewerColour.setToolTipText(MessageManager
163 .getString("label.let_jmol_manage_structure_colours"));
167 * display a single PDB structure in a new Jmol view
174 public AppJmol(PDBEntry pdbentry, SequenceI[] seq, String[] chains,
175 final AlignmentPanel ap)
177 setProgressIndicator(ap.alignFrame);
179 openNewJmol(ap, alignAddedStructures, new PDBEntry[] { pdbentry },
184 private void openNewJmol(AlignmentPanel ap, boolean alignAdded,
185 PDBEntry[] pdbentrys, SequenceI[][] seqs)
187 setProgressIndicator(ap.alignFrame);
188 jmb = new AppJmolBinding(this, ap.getStructureSelectionManager(),
189 pdbentrys, seqs, null);
190 addAlignmentPanel(ap);
191 useAlignmentPanelForColourbyseq(ap);
193 alignAddedStructures = alignAdded;
194 if (pdbentrys.length > 1)
196 useAlignmentPanelForSuperposition(ap);
199 jmb.setColourBySequence(true);
200 setSize(400, 400); // probably should be a configurable/dynamic default here
202 addingStructures = false;
203 worker = new Thread(this);
206 this.addInternalFrameListener(new InternalFrameAdapter()
209 public void internalFrameClosing(
210 InternalFrameEvent internalFrameEvent)
219 * create a new Jmol containing several structures optionally superimposed
220 * using the given alignPanel.
224 * - true to superimpose
228 public AppJmol(AlignmentPanel ap, boolean alignAdded, PDBEntry[] pe,
231 openNewJmol(ap, alignAdded, pe, seqs);
234 void initJmol(String command)
236 jmb.setFinishedInit(false);
237 renderPanel = new RenderPanel();
238 // TODO: consider waiting until the structure/view is fully loaded before
240 this.getContentPane().add(renderPanel, java.awt.BorderLayout.CENTER);
241 jalview.gui.Desktop.addInternalFrame(this, jmb.getViewerTitle(),
242 getBounds().width, getBounds().height);
243 if (scriptWindow == null)
245 BorderLayout bl = new BorderLayout();
248 scriptWindow = new JPanel(bl);
249 scriptWindow.setVisible(false);
252 jmb.allocateViewer(renderPanel, true, "", null, null, "", scriptWindow,
254 // jmb.newJmolPopup("Jmol");
259 jmb.executeCommand(new StructureCommand(command), false);
260 jmb.executeCommand(new StructureCommand("set hoverDelay=0.1"), false);
261 jmb.setFinishedInit(true);
270 List<String> files = jmb.fetchPdbFiles(this);
271 if (files.size() > 0)
273 showFilesInViewer(files);
283 * Either adds the given files to a structure viewer or opens a new viewer to
287 * list of absolute paths to structure files
289 void showFilesInViewer(List<String> files)
291 long lastnotify = jmb.getLoadNotifiesHandled();
292 StringBuilder fileList = new StringBuilder();
293 for (String s : files)
295 fileList.append(SPACE).append(QUOTE)
296 .append(Platform.escapeBackslashes(s)).append(QUOTE);
298 String filesString = fileList.toString();
300 if (!addingStructures)
304 initJmol("load FILES " + filesString);
305 } catch (OutOfMemoryError oomerror)
307 new OOMWarning("When trying to open the Jmol viewer!", oomerror);
308 Console.debug("File locations are " + filesString);
309 } catch (Exception ex)
311 Console.error("Couldn't open Jmol viewer!", ex);
312 ex.printStackTrace();
318 StringBuilder cmd = new StringBuilder();
319 cmd.append("loadingJalviewdata=true\nload APPEND ");
320 cmd.append(filesString);
321 cmd.append("\nloadingJalviewdata=null");
322 final StructureCommand command = new StructureCommand(cmd.toString());
323 lastnotify = jmb.getLoadNotifiesHandled();
327 jmb.executeCommand(command, false);
328 } catch (OutOfMemoryError oomerror)
330 new OOMWarning("When trying to add structures to the Jmol viewer!",
332 Console.debug("File locations are " + filesString);
334 } catch (Exception ex)
336 Console.error("Couldn't add files to Jmol viewer!", ex);
337 ex.printStackTrace();
342 // need to wait around until script has finished
343 int waitMax = JMOL_LOAD_TIMEOUT;
346 while (addingStructures ? lastnotify >= jmb.getLoadNotifiesHandled()
347 : !(jmb.isFinishedInit() && jmb.getStructureFiles() != null
348 && jmb.getStructureFiles().length == files.size()))
352 Console.debug("Waiting around for jmb notify.");
353 waitTotal += waitFor;
355 // Thread.sleep() throws an exception in JS
356 Thread.sleep(waitFor);
357 } catch (Exception e)
360 if (waitTotal > waitMax)
362 System.err.println("Timed out waiting for Jmol to load files after "
364 // System.err.println("finished: " + jmb.isFinishedInit()
365 // + "; loaded: " + Arrays.toString(jmb.getPdbFile())
366 // + "; files: " + files.toString());
367 jmb.getStructureFiles();
372 // refresh the sequence colours for the new structure(s)
373 for (AlignmentViewPanel ap : _colourwith)
375 jmb.updateColours(ap);
377 // do superposition if asked to
378 if (alignAddedStructures)
380 alignAddedStructures();
382 addingStructures = false;
386 * Queues a thread to align structures with Jalview alignments
388 void alignAddedStructures()
390 javax.swing.SwingUtilities.invokeLater(new Runnable()
395 if (jmb.jmolViewer.isScriptExecuting())
397 SwingUtilities.invokeLater(this);
401 } catch (InterruptedException q)
408 alignStructsWithAllAlignPanels();
416 * Outputs the Jmol viewer image as an image file, after prompting the user to
417 * choose a file and (for EPS) choice of Text or Lineart character rendering
418 * (unless a preference for this is set)
423 public void makePDBImage(ImageMaker.TYPE type)
425 int width = getWidth();
426 int height = getHeight();
427 ImageWriterI writer = new ImageWriterI()
430 public void exportImage(Graphics g) throws Exception
432 jmb.jmolViewer.renderScreenImage(g, width, height);
435 String view = MessageManager.getString("action.view")
436 .toLowerCase(Locale.ROOT);
437 ImageExporter exporter = new ImageExporter(writer,
438 getProgressIndicator(), type, getTitle());
439 exporter.doExport(null, this, width, height, view);
443 public void showHelp_actionPerformed()
447 BrowserLauncher // BH 2018
448 .openURL("http://wiki.jmol.org");// http://jmol.sourceforge.net/docs/JmolUserGuide/");
449 } catch (Exception ex)
451 System.err.println("Show Jmol help failed with: " + ex.getMessage());
456 public void showConsole(boolean showConsole)
461 if (splitPane == null)
463 splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
464 splitPane.setTopComponent(renderPanel);
465 splitPane.setBottomComponent(scriptWindow);
466 this.getContentPane().add(splitPane, BorderLayout.CENTER);
467 splitPane.setDividerLocation(getHeight() - 200);
468 scriptWindow.setVisible(true);
469 scriptWindow.validate();
470 splitPane.validate();
476 if (splitPane != null)
478 splitPane.setVisible(false);
483 this.getContentPane().add(renderPanel, BorderLayout.CENTER);
489 class RenderPanel extends JPanel
491 final Dimension currentSize = new Dimension();
494 public void paintComponent(Graphics g)
496 getSize(currentSize);
498 if (jmb != null && jmb.hasFileLoadingError())
500 g.setColor(Color.black);
501 g.fillRect(0, 0, currentSize.width, currentSize.height);
502 g.setColor(Color.white);
503 g.setFont(new Font("Verdana", Font.BOLD, 14));
504 g.drawString(MessageManager.getString("label.error_loading_file")
505 + "...", 20, currentSize.height / 2);
506 StringBuffer sb = new StringBuffer();
508 for (int e = 0; e < jmb.getPdbCount(); e++)
510 sb.append(jmb.getPdbEntry(e).getId());
511 if (e < jmb.getPdbCount() - 1)
516 if (e == jmb.getPdbCount() - 1 || sb.length() > 20)
519 g.drawString(sb.toString(), 20, currentSize.height / 2
520 - lines * g.getFontMetrics().getHeight());
524 else if (jmb == null || jmb.jmolViewer == null
525 || !jmb.isFinishedInit())
527 g.setColor(Color.black);
528 g.fillRect(0, 0, currentSize.width, currentSize.height);
529 g.setColor(Color.white);
530 g.setFont(new Font("Verdana", Font.BOLD, 14));
531 g.drawString(MessageManager.getString("label.retrieving_pdb_data"),
532 20, currentSize.height / 2);
536 jmb.jmolViewer.renderScreenImage(g, currentSize.width,
543 public AAStructureBindingModel getBinding()
549 public ViewerType getViewerType()
551 return ViewerType.JMOL;
555 protected String getViewerName()