From 2a38a45cf356c9edaaef4ec74aa83b6f76609514 Mon Sep 17 00:00:00 2001 From: jprocter Date: Fri, 27 Aug 2010 15:44:06 +0000 Subject: [PATCH] refactored seq/str binding methods and ensured that structures added to existing view get loaded first --- src/jalview/gui/AppJmol.java | 329 ++++++++++++++++++++++++++--------- src/jalview/gui/AppJmolBinding.java | 194 +-------------------- 2 files changed, 250 insertions(+), 273 deletions(-) diff --git a/src/jalview/gui/AppJmol.java b/src/jalview/gui/AppJmol.java index df4efd9..c361ab9 100644 --- a/src/jalview/gui/AppJmol.java +++ b/src/jalview/gui/AppJmol.java @@ -57,6 +57,8 @@ public class AppJmol extends GStructureViewer implements Runnable, Vector atomsPicked = new Vector(); + private boolean addingStructures = false; + public AppJmol(String file, String id, SequenceI[] seq, AlignmentPanel ap, String loadStatus, Rectangle bounds) { @@ -73,7 +75,8 @@ public class AppJmol extends GStructureViewer implements Runnable, // / TODO: check if protocol is needed to be set, and if chains are // autodiscovered. jmb = new AppJmolBinding(this, new PDBEntry[] - { pdbentry }, new SequenceI[][] { seq }, null, null); + { pdbentry }, new SequenceI[][] + { seq }, null, null); jmb.setLoadingFromArchive(true); this.ap = ap; @@ -106,14 +109,11 @@ public class AppJmol extends GStructureViewer implements Runnable, if (alreadyMapped != null) { - int option = JOptionPane - .showInternalConfirmDialog( - Desktop.desktop, - pdbentry.getId() - + " is already displayed." - + "\nDo you want to re-use this viewer ?", - "Map Sequences to Visible Window: " - + pdbentry.getId(), JOptionPane.YES_NO_OPTION); + int option = JOptionPane.showInternalConfirmDialog(Desktop.desktop, + pdbentry.getId() + " is already displayed." + + "\nDo you want to re-use this viewer ?", + "Map Sequences to Visible Window: " + pdbentry.getId(), + JOptionPane.YES_NO_OPTION); if (option == JOptionPane.YES_OPTION) { @@ -155,22 +155,21 @@ public class AppJmol extends GStructureViewer implements Runnable, // Check if there are other Jmol views involving this alignment // and prompt user about adding this molecule to one of them Vector existingViews = getJmolsFor(ap); - if (existingViews.size()>0) + if (existingViews.size() > 0) { Enumeration jm = existingViews.elements(); - while (jm.hasMoreElements()) { + while (jm.hasMoreElements()) + { AppJmol topJmol = (AppJmol) jm.nextElement(); // TODO: highlight topJmol in view somehow - int option = JOptionPane - .showInternalConfirmDialog( - Desktop.desktop, "Do you want to add "+ - pdbentry.getId()+" to the view called\n'"+topJmol.getTitle() - + "'\n", - "Align to existing structure view" - , JOptionPane.YES_NO_OPTION); + int option = JOptionPane.showInternalConfirmDialog(Desktop.desktop, + "Do you want to add " + pdbentry.getId() + + " to the view called\n'" + topJmol.getTitle() + + "'\n", "Align to existing structure view", + JOptionPane.YES_NO_OPTION); if (option == JOptionPane.YES_OPTION) { - topJmol.jmb.addStructure(pdbentry, seq, chains,true); + topJmol.addStructure(pdbentry, seq, chains, true); return; } } @@ -178,7 +177,8 @@ public class AppJmol extends GStructureViewer implements Runnable, // ///////////////////////////////// jmb = new AppJmolBinding(this, new PDBEntry[] - { pdbentry }, new SequenceI[][]{seq}, null, null); + { pdbentry }, new SequenceI[][] + { seq }, null, null); this.ap = ap; setSize(400, 400); // probably should be a configurable/dynamic default here @@ -188,7 +188,8 @@ public class AppJmol extends GStructureViewer implements Runnable, } else { - Thread worker = new Thread(this); + addingStructures = false; + worker = new Thread(this); worker.start(); } @@ -202,9 +203,66 @@ public class AppJmol extends GStructureViewer implements Runnable, } + /** + * pdb retrieval thread. + */ + 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 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) + { + 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); + } + }).start(); + return; + } + } + // otherwise, start adding the structure. + jmb.addSequenceAndChain(new PDBEntry[] + { pdbentry }, new SequenceI[][] + { seq }, new String[][] + { chains }); + addingStructures = true; + _started = false; + (worker = new Thread(this)).start(); + return; + } + private Vector getJmolsFor(AlignmentPanel ap2) { - Vector otherJmols= new Vector(); + Vector otherJmols = new Vector(); // Now this AppJmol is mapped to new sequences. We must add them to // the exisiting array JInternalFrame[] frames = Desktop.instance.getAllFrames(); @@ -214,7 +272,7 @@ public class AppJmol extends GStructureViewer implements Runnable, if (frames[i] instanceof AppJmol) { AppJmol topJmol = ((AppJmol) frames[i]); - if (topJmol.ap==ap2) + if (topJmol.ap == ap2) { otherJmols.addElement(topJmol); } @@ -241,7 +299,7 @@ public class AppJmol extends GStructureViewer implements Runnable, void setChainMenuItems(Vector chains) { chainMenu.removeAll(); - if (chains==null) + if (chains == null) { return; } @@ -281,6 +339,8 @@ public class AppJmol extends GStructureViewer implements Runnable, boolean allChainsSelected = false; + private boolean alignAddedStructures = false; + void centerViewer() { Vector toshow = new Vector(); @@ -308,41 +368,83 @@ public class AppJmol extends GStructureViewer implements Runnable, jmb = null; } + /** + * state flag for PDB retrieval thread + */ + private boolean _started = false; + public void run() { + _started = true; String pdbid = ""; // todo - record which pdbids were successfuly imported. StringBuffer errormsgs = new StringBuffer(), files = new StringBuffer(); try { + String[] curfiles = jmb.getPdbFile(); // files currently in viewer // TODO: replace with reference fetching/transfer code (validate PDBentry // as a DBRef?) jalview.ws.dbsources.Pdb pdbclient = new jalview.ws.dbsources.Pdb(); for (int pi = 0; pi < jmb.pdbentry.length; pi++) { - AlignmentI pdbseq; - if ((pdbseq = pdbclient.getSequenceRecords(pdbid = jmb.pdbentry[pi] - .getId())) != null) + String file = jmb.pdbentry[pi].getFile(); + if (file == null) { - String file; - // just transfer the file name from the first sequence's first - // PDBEntry - jmb.pdbentry[pi].setFile(file = ((PDBEntry) pdbseq.getSequenceAt( - 0).getPDBId().elementAt(0)).getFile()); - files.append("\"" + file + "\""); + // retrieve the pdb and store it locally + AlignmentI pdbseq = null; + try + { + pdbseq = pdbclient.getSequenceRecords(pdbid = jmb.pdbentry[pi] + .getId()); + } catch (OutOfMemoryError oomerror) + { + new OOMWarning("Retrieving PDB id " + pdbid, oomerror); + } catch (Exception ex) + { + ex.printStackTrace(); + errormsgs.append("'" + pdbid + "'"); + } + if (pdbseq != null) + { + // just transfer the file name from the first sequence's first + // PDBEntry + jmb.pdbentry[pi].setFile(file = ((PDBEntry) pdbseq + .getSequenceAt(0).getPDBId().elementAt(0)).getFile()); + files.append(" \"" + file + "\""); + } + else + { + errormsgs.append("'" + pdbid + "' "); + } } else { - errormsgs.append("'" + pdbid + "' "); + if (curfiles != null && curfiles.length > 0) + { + addingStructures = true; // already files loaded. + for (int c = 0; c < curfiles.length; c++) + { + if (curfiles[c].equals(file)) + { + file = null; + break; + } + } + } + if (file != null) + { + files.append(" \"" + file + "\""); + } } } } catch (OutOfMemoryError oomerror) { - new OOMWarning("Retrieving PDB id " + pdbid, oomerror); + new OOMWarning("Retrieving PDB files: " + pdbid, oomerror); } catch (Exception ex) { ex.printStackTrace(); - errormsgs.append("'" + pdbid + "'"); + errormsgs.append("When retrieving pdbfiles : current was: '" + pdbid + + "'"); } if (errormsgs.length() > 0) { @@ -356,24 +458,74 @@ public class AppJmol extends GStructureViewer implements Runnable, } if (files.length() > 0) { + if (!addingStructures) + { + + try + { + initJmol("load FILES " + files.toString()); + } catch (OutOfMemoryError oomerror) + { + new OOMWarning("When trying to open the Jmol viewer!", oomerror); + Cache.log.debug("File locations are " + files); + } catch (Exception ex) + { + Cache.log.error("Couldn't open Jmol viewer!", ex); + } + } + else + { + StringBuffer cmd = new StringBuffer(); + cmd.append("load APPEND "); + cmd.append(files.toString()); + cmd.append("\n"); + final String command = cmd.toString(); + cmd = null; try { - initJmol("load FILES " + files.toString()); + jmb.evalStateCommand(command); } catch (OutOfMemoryError oomerror) { - new OOMWarning("When trying to open the Jmol viewer!", oomerror); + new OOMWarning("When trying to add structures to the Jmol viewer!", + oomerror); Cache.log.debug("File locations are " + files); } catch (Exception ex) { - Cache.log.error("Couldn't open Jmol viewer!", ex); + Cache.log.error("Couldn't add files to Jmol viewer!", ex); } + if (alignAddedStructures) + { + // may need to wait around until script has finished + while (jmb.viewer.isScriptExecuting()) + { + try + { + Thread.sleep(20); + } catch (Exception e) + { + } + ; + } + javax.swing.SwingUtilities.invokeLater(new Runnable() + { + public void run() + { + jmb.superposeStructures(ap.av.getAlignment(), -1, null); + } + }); + alignAddedStructures = false; + } + addingStructures = false; } + } + _started = false; + worker = null; } public void pdbFile_actionPerformed(ActionEvent actionEvent) { - JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache - .getProperty("LAST_DIRECTORY")); + JalviewFileChooser chooser = new JalviewFileChooser( + jalview.bin.Cache.getProperty("LAST_DIRECTORY")); chooser.setFileView(new JalviewFileView()); chooser.setDialogTitle("Save PDB File"); @@ -385,8 +537,9 @@ public class AppJmol extends GStructureViewer implements Runnable, { try { - // TODO: cope with multiple PDB files in view - BufferedReader in = new BufferedReader(new FileReader(jmb.getPdbFile()[0])); + // TODO: cope with multiple PDB files in view + BufferedReader in = new BufferedReader(new FileReader( + jmb.getPdbFile()[0])); File outFile = chooser.getSelectedFile(); PrintWriter out = new PrintWriter(new FileOutputStream(outFile)); @@ -409,13 +562,20 @@ public class AppJmol extends GStructureViewer implements Runnable, public void viewMapping_actionPerformed(ActionEvent actionEvent) { jalview.gui.CutAndPasteTransfer cap = new jalview.gui.CutAndPasteTransfer(); - try {for (int pdbe = 0; pdbe20) + if (e == jmb.pdbentry.length - 1 || sb.length() > 20) { lines++; - g.drawString(sb.toString(), 20, currentSize.height/2 - lines*g.getFontMetrics().getHeight()); + g.drawString(sb.toString(), 20, currentSize.height / 2 - lines + * g.getFontMetrics().getHeight()); } } } + else if (jmb == null || jmb.viewer == null || !jmb.isFinishedInit()) + { + g.setColor(Color.black); + g.fillRect(0, 0, currentSize.width, currentSize.height); + g.setColor(Color.white); + g.setFont(new Font("Verdana", Font.BOLD, 14)); + g.drawString("Retrieving PDB data....", 20, currentSize.height / 2); + } else - if (jmb == null || jmb.viewer == null || !jmb.isFinishedInit()) - { - g.setColor(Color.black); - g.fillRect(0, 0, currentSize.width, currentSize.height); - g.setColor(Color.white); - g.setFont(new Font("Verdana", Font.BOLD, 14)); - g.drawString("Retrieving PDB data....", 20, currentSize.height / 2); - } - else { jmb.viewer.renderScreenImage(g, currentSize, rectClip); } @@ -653,6 +813,7 @@ public class AppJmol extends GStructureViewer implements Runnable, } return viewId; } + public void updateTitleAndMenus() { if (jmb.fileLoadingError != null && jmb.fileLoadingError.length() > 0) @@ -662,33 +823,41 @@ public class AppJmol extends GStructureViewer implements Runnable, } setChainMenuItems(jmb.chainNames); jmb.colourBySequence(ap.av.getShowSequenceFeatures(), ap.av.alignment); - + this.setTitle(jmb.getViewerTitle()); - if (jmb.getPdbFile().length>1 && jmb.sequence.length>1) { - jmolActionMenu.setVisible(true); + if (jmb.getPdbFile().length > 1 && jmb.sequence.length > 1) + { + jmolActionMenu.setVisible(true); } } - /* (non-Javadoc) - * @see jalview.jbgui.GStructureViewer#alignStructs_actionPerformed(java.awt.event.ActionEvent) + /* + * (non-Javadoc) + * + * @see + * jalview.jbgui.GStructureViewer#alignStructs_actionPerformed(java.awt.event + * .ActionEvent) */ @Override protected void alignStructs_actionPerformed(ActionEvent actionEvent) { - - try { - jmb.superposeStructures(ap.av.getAlignment(), -1, ap.av.getColumnSelection()); + + try + { + jmb.superposeStructures(ap.av.getAlignment(), -1, + ap.av.getColumnSelection()); } catch (Exception e) { - Cache.log.info("Couldn't align structures in alignframe "+ap.alignFrame.getTitle(),e); - + Cache.log.info("Couldn't align structures in alignframe " + + ap.alignFrame.getTitle(), e); + } } public void setJalviewColourScheme(ColourSchemeI ucs) { jmb.setJalviewColourScheme(ucs); - + } } diff --git a/src/jalview/gui/AppJmolBinding.java b/src/jalview/gui/AppJmolBinding.java index d6535e3..d2efb93 100644 --- a/src/jalview/gui/AppJmolBinding.java +++ b/src/jalview/gui/AppJmolBinding.java @@ -4,7 +4,6 @@ package jalview.gui; import java.util.BitSet; -import java.util.Vector; import jalview.bin.Cache; import jalview.datamodel.PDBEntry; @@ -12,7 +11,7 @@ import jalview.datamodel.SequenceI; import org.jmol.popup.JmolPopup; -class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding +public class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding { /** @@ -119,144 +118,6 @@ class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding asPopup); } - /** - * add structures and any known sequence associations - * - * @returns the pdb entries added to the current set. - */ - private PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe, - SequenceI[][] seq, String[][] chns) - { - int pe = -1; - Vector v = new Vector(); - Vector rtn = new Vector(); - for (int i = 0; i < pdbentry.length; i++) - { - v.addElement(pdbentry[i]); - } - for (int i = 0; i < pdbe.length; i++) - { - int r = v.indexOf(pdbe[i]); - if (r == -1 || r >= pdbentry.length) - { - rtn.addElement(new int[] - { v.size(), i }); - v.addElement(pdbe[i]); - } - else - { - // just make sure the sequence/chain entries are all up to date - addSequenceAndChain(r, seq[i], chns[i]); - } - } - pdbe = new PDBEntry[v.size()]; - v.copyInto(pdbe); - pdbentry = pdbe; - if (rtn.size() > 0) - { - // expand the tied seuqence[] and string[] arrays - SequenceI[][] sqs = new SequenceI[pdbentry.length][]; - String[][] sch = new String[pdbentry.length][]; - System.arraycopy(sequence, 0, sqs, 0, sequence.length); - System.arraycopy(chains, 0, sch, 0, this.chains.length); - sequence = sqs; - chains = sch; - pdbe = new PDBEntry[rtn.size()]; - for (int r = 0; r < pdbe.length; r++) - { - int[] stri = ((int[]) rtn.elementAt(r)); - // record the pdb file as a new addition - pdbe[r] = pdbentry[stri[0]]; - // and add the new sequence/chain entries - addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]); - } - } - else - { - pdbe = null; - } - return pdbe; - } - - void addSequence(int pe, SequenceI[] seq) - { - // add sequences to the pe'th pdbentry's seuqence set. - addSequenceAndChain(pe, seq, null); - } - - private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain) - { - if (pe < 0 || pe >= pdbentry.length) - { - throw new Error( - "Implementation error - no corresponding pdbentry (for index " - + pe + ") to add sequences mappings to"); - } - final String nullChain = "TheNullChain"; - Vector s = new Vector(); - Vector c = new Vector(); - if (chains == null) - { - chains = new String[pdbentry.length][]; - } - if (sequence[pe] != null) - { - for (int i = 0; i < sequence[pe].length; i++) - { - s.addElement(sequence[pe][i]); - if (chains[pe] != null) - { - if (i < chains[pe].length) - { - c.addElement(chains[pe][i]); - } - else - { - c.addElement(nullChain); - } - } - else - { - if (tchain != null && tchain.length > 0) - { - c.addElement(nullChain); - } - } - } - } - for (int i = 0; i < seq.length; i++) - { - if (!s.contains(seq[i])) - { - s.addElement(seq[i]); - if (tchain != null && i < tchain.length) - { - c.addElement(tchain[i] == null ? nullChain : tchain[i]); - } - } - } - SequenceI[] tmp = new SequenceI[s.size()]; - s.copyInto(tmp); - sequence[pe] = tmp; - if (c.size() > 0) - { - String[] tch = new String[c.size()]; - c.copyInto(tch); - for (int i = 0; i < tch.length; i++) - { - if (tch[i] == nullChain) - { - tch[i] = null; - } - } - chains[pe] = tch; - } - else - { - chains[pe] = null; - } - } - public void selectionChanged(BitSet arg0) { // TODO Auto-generated method stub @@ -269,59 +130,6 @@ class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding } - /** - * add another pdb entry into the view, with associated sequences and chains - * - * @param pdbentry - * @param seq - * @param chains - * @param align - * if true, new structure(s) will be align using associated alignment - */ - public synchronized void addStructure(PDBEntry pdbentry, SequenceI[] seq, - String[] chains, final boolean align) - { - PDBEntry[] pe = addSequenceAndChain(new PDBEntry[] - { pdbentry }, new SequenceI[][] - { seq }, new String[][] - { chains }); - if (pe != null) - { - StringBuffer cmd = new StringBuffer(); - cmd.append("load APPEND"); - for (int p = 0; p < pe.length; p++) - { - cmd.append(" \""); - cmd.append(pe[p].getFile()); - cmd.append("\""); - } - cmd.append("\n"); - final String command = cmd.toString(); - cmd = null; - new Thread(new Runnable() - { - public void run() - { - evalStateCommand(command); - if (align) - { - // may need to wait around until script has finished - while (viewer.isScriptExecuting()) - { - try - { - Thread.sleep(20); - } catch (Exception e) - { - } - ; - } - superposeStructures(appJmolWindow.ap.av.getAlignment(), -1, null); - } - } - }).start(); - } - } /** * add the given sequences to the mapping scope for the given pdb file handle -- 1.7.10.2