037b97e1ce9c889037047c5bbea7839cec939cd7
[jalview.git] / src / jalview / gui / AppJmolBinding.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
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.
11  *  
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.
16  * 
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.
20  */
21 package jalview.gui;
22
23 import java.awt.Container;
24 import java.io.File;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.Map;
28
29 import javax.swing.JComponent;
30
31 import org.jmol.api.JmolAppConsoleInterface;
32 import org.openscience.jmol.app.jmolpanel.console.AppConsole;
33
34 import jalview.api.AlignmentViewPanel;
35 import jalview.api.structures.JalviewStructureDisplayI;
36 import jalview.bin.Cache;
37 import jalview.datamodel.AlignmentI;
38 import jalview.datamodel.PDBEntry;
39 import jalview.datamodel.SequenceI;
40 import jalview.ext.jmol.JalviewJmolBinding;
41 import jalview.io.DataSourceType;
42 import jalview.structure.StructureSelectionManager;
43 import jalview.util.MessageManager;
44 import jalview.util.Platform;
45 import jalview.ws.dbsources.EBIAlfaFold;
46 import jalview.ws.dbsources.Pdb;
47 import jalview.ws.utils.UrlDownloadClient;
48 import javajs.util.BS;
49
50 public class AppJmolBinding extends JalviewJmolBinding
51 {
52   public AppJmolBinding(AppJmol appJmol, StructureSelectionManager sSm,
53           PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
54           DataSourceType protocol)
55   {
56     super(sSm, pdbentry, sequenceIs, protocol);
57     setViewer(appJmol);
58   }
59
60   @Override
61   public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment)
62   {
63     return new SequenceRenderer(((AlignmentPanel) alignment).av);
64   }
65
66   @Override
67   public void sendConsoleEcho(String strEcho)
68   {
69     if (console != null)
70     {
71       console.sendConsoleEcho(strEcho);
72     }
73   }
74
75   @Override
76   public void sendConsoleMessage(String strStatus)
77   {
78     if (console != null && strStatus != null)
79     // && !strStatus.equals("Script completed"))
80     // should we squash the script completed string ?
81     {
82       console.sendConsoleMessage(strStatus);
83     }
84   }
85
86   @Override
87   public void showUrl(String url, String target)
88   {
89     try
90     {
91       jalview.util.BrowserLauncher.openURL(url);
92     } catch (Exception e)
93     {
94       Cache.log.error("Failed to launch Jmol-associated url " + url, e);
95       // TODO: 2.6 : warn user if browser was not configured.
96     }
97   }
98
99   @Override
100   public void refreshGUI()
101   {
102     if (getMappedStructureCount() == 0)
103     {
104       // too soon!
105       return;
106     }
107     // appJmolWindow.repaint();
108     javax.swing.SwingUtilities.invokeLater(new Runnable()
109     {
110       @Override
111       public void run()
112       {
113         JalviewStructureDisplayI theViewer = getViewer();
114         // invokes colourbySequence() via seqColour_ActionPerformed()
115         theViewer.updateTitleAndMenus();
116         ((JComponent) theViewer).revalidate();
117       }
118     });
119   }
120
121   @Override
122   public void notifyScriptTermination(String strStatus, int msWalltime)
123   {
124     // todo - script termination doesn't happen ?
125     // if (console != null)
126     // console.notifyScriptTermination(strStatus,
127     // msWalltime);
128   }
129
130   @Override
131   public void showUrl(String url)
132   {
133     showUrl(url, "jmol");
134   }
135
136   public void newJmolPopup(String menuName)
137   {
138     // jmolpopup = new JmolAwtPopup();
139     // jmolpopup.jpiInitialize((viewer), menuName);
140   }
141
142   @Override
143   public void selectionChanged(BS arg0)
144   {
145   }
146
147   @Override
148   public void showConsole(boolean b)
149   {
150     getViewer().showConsole(b);
151   }
152
153   @Override
154   protected JmolAppConsoleInterface createJmolConsole(
155           Container consolePanel, String buttonsToShow)
156   {
157     jmolViewer.setJmolCallbackListener(this);
158     // BH comment: can't do this yet [for JS only, or generally?]
159     return Platform.isJS() ? null
160             : new AppConsole(jmolViewer, consolePanel, buttonsToShow);
161   }
162
163   @Override
164   protected void releaseUIResources()
165   {
166     setViewer(null);
167     closeConsole();
168   }
169
170   @Override
171   public void releaseReferences(Object svl)
172   {
173     if (svl instanceof SeqPanel)
174     {
175       getViewer().removeAlignmentPanel(((SeqPanel) svl).ap);
176     }
177   }
178
179   @Override
180   public Map<String, Object> getJSpecViewProperty(String arg0)
181   {
182     // TODO Auto-generated method stub
183     return null;
184   }
185
186   @SuppressWarnings("unused")
187   public void cacheFiles(List<File> files)
188   {
189     if (files == null)
190     {
191       return;
192     }
193     for (File f : files)
194     {
195       Platform.cacheFileData(f);
196     }
197   }
198
199   /**
200    * Retrieves and saves as file any modelled PDB entries for which we do not
201    * already have a file saved. Returns a list of absolute paths to structure
202    * files which were either retrieved, or already stored but not modelled in
203    * the structure viewer (i.e. files to add to the viewer display).
204    * 
205    * Currently only used by Jmol - similar but different code used for Chimera/X
206    * and Pymol so still need to refactor
207    * 
208    * @param structureViewer
209    *          UI proxy for the structure viewer
210    * @return list of absolute paths to structures retrieved that need to be
211    *         added to the display
212    */
213   public List<String> fetchPdbFiles(StructureViewerBase structureViewer)
214   {
215     // todo - record which pdbids were successfully imported.
216     StringBuilder errormsgs = new StringBuilder();
217   
218     List<String> files = new ArrayList<>();
219     String pdbid = "";
220     try
221     {
222       String[] filesInViewer = getStructureFiles();
223       // TODO: replace with reference fetching/transfer code (validate PDBentry
224       // as a DBRef?)
225       Pdb pdbclient = new Pdb();
226       EBIAlfaFold afclient = new EBIAlfaFold();
227       
228       for (int pi = 0; pi < getPdbCount(); pi++)
229       {
230         String file = getPdbEntry(pi).getFile();
231         if (file == null)
232         {
233           // todo: extract block as method and pull up (also ChimeraViewFrame)
234           // retrieve the pdb and store it locally
235           AlignmentI pdbseq = null;
236           PDBEntry strucEntry = getPdbEntry(pi);
237           pdbid = strucEntry.getId();
238           long hdl = pdbid.hashCode() - System.currentTimeMillis();
239           structureViewer.setProgressMessage(MessageManager
240                   .formatMessage("status.fetching_pdb", new String[]
241                   { pdbid }), hdl);
242           try
243           {
244             if (afclient.isValidReference(pdbid))
245             {
246               pdbseq = afclient.getSequenceRecords(pdbid);
247             } else {
248               if (strucEntry.hasRetrievalUrl())
249               {
250                 File tmpFile = File.createTempFile(pdbid, ".cif");
251                 String fromUrl = strucEntry.getRetrievalUrl();
252                 UrlDownloadClient.download(fromUrl, tmpFile);
253                 
254                 // may not need this check ?
255                 file = tmpFile.getAbsolutePath();
256                 if (file != null)
257                 {
258                   pdbseq = EBIAlfaFold.importDownloadedStructureFromUrl(fromUrl,tmpFile,pdbid,null,null,null);
259                 }
260               } else {
261                 pdbseq = pdbclient.getSequenceRecords(pdbid);
262               }
263             }
264           } catch (OutOfMemoryError oomerror)
265           {
266             new OOMWarning("Retrieving PDB id " + pdbid, oomerror);
267           } catch (Exception ex)
268           {
269             ex.printStackTrace();
270             errormsgs.append("'").append(pdbid).append("'");
271           } finally
272           {
273             structureViewer.setProgressMessage(
274                     MessageManager.getString("label.state_completed"), hdl);
275           }
276           if (pdbseq != null)
277           {
278             // just transfer the file name from the first sequence's first
279             // PDBEntry
280             file = new File(pdbseq.getSequenceAt(0).getAllPDBEntries()
281                     .elementAt(0).getFile()).getAbsolutePath();
282             getPdbEntry(pi).setFile(file);
283             files.add(file);
284           }
285           else
286           {
287             errormsgs.append("'").append(pdbid).append("' ");
288           }
289         }
290         else
291         {
292           if (filesInViewer != null && filesInViewer.length > 0)
293           {
294             structureViewer.setAddingStructures(true); // already files loaded.
295             for (int c = 0; c < filesInViewer.length; c++)
296             {
297               if (Platform.pathEquals(filesInViewer[c], file))
298               {
299                 file = null;
300                 break;
301               }
302             }
303           }
304           if (file != null)
305           {
306             files.add(file);
307           }
308         }
309       }
310     } catch (OutOfMemoryError oomerror)
311     {
312       new OOMWarning("Retrieving PDB files: " + pdbid, oomerror);
313     } catch (Exception ex)
314     {
315       ex.printStackTrace();
316       errormsgs.append("When retrieving pdbfiles : current was: '")
317               .append(pdbid).append("'");
318     }
319     if (errormsgs.length() > 0)
320     {
321       JvOptionPane.showInternalMessageDialog(Desktop.desktop,
322               MessageManager.formatMessage(
323                       "label.pdb_entries_couldnt_be_retrieved", new String[]
324                       { errormsgs.toString() }),
325               MessageManager.getString("label.couldnt_load_file"),
326               JvOptionPane.ERROR_MESSAGE);
327     }
328     return files;
329   }
330
331 }