revised sequence/structure binding so one structure associated with x-seuqenceI's...
[jalview.git] / src / jalview / gui / AppJmolBinding.java
1 /**
2  * 
3  */
4 package jalview.gui;
5
6 import java.util.BitSet;
7 import java.util.Vector;
8
9 import jalview.bin.Cache;
10 import jalview.datamodel.PDBEntry;
11 import jalview.datamodel.SequenceI;
12
13 import org.jmol.popup.JmolPopup;
14
15 class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
16 {
17
18   /**
19    * 
20    */
21   private AppJmol appJmolWindow;
22
23   public AppJmolBinding(AppJmol appJmol, PDBEntry[] pdbentry,
24           SequenceI[][] sequenceIs, String[][] chains, String protocol)
25   {
26     super(pdbentry, sequenceIs, chains, protocol);
27     appJmolWindow = appJmol;
28   }
29
30   FeatureRenderer fr = null;
31
32   @Override
33   public jalview.api.FeatureRenderer getFeatureRenderer()
34   {
35     if (appJmolWindow.ap.av.showSequenceFeatures)
36     {
37       if (fr == null)
38       {
39         fr = new FeatureRenderer(appJmolWindow.ap);
40       }
41
42       fr.transferSettings(appJmolWindow.ap.seqPanel.seqCanvas
43               .getFeatureRenderer());
44     }
45
46     return fr;
47   }
48
49   @Override
50   public jalview.api.SequenceRenderer getSequenceRenderer()
51   {
52     return new SequenceRenderer(appJmolWindow.ap.av);
53   }
54
55   public void sendConsoleEcho(String strEcho)
56   {
57     if (appJmolWindow.scriptWindow != null)
58     {
59       appJmolWindow.scriptWindow.sendConsoleEcho(strEcho);
60     }
61   }
62
63   public void sendConsoleMessage(String strStatus)
64   {
65     if (appJmolWindow.scriptWindow != null && strStatus != null)
66     // && !strStatus.equals("Script completed"))
67     // should we squash the script completed string ?
68     {
69       appJmolWindow.scriptWindow.sendConsoleMessage(strStatus);
70     }
71   }
72
73   @Override
74   public void showUrl(String url, String target)
75   {
76     try
77     {
78       jalview.util.BrowserLauncher.openURL(url);
79     } catch (Exception e)
80     {
81       Cache.log.error("Failed to launch Jmol-associated url " + url, e);
82       // TODO: 2.6 : warn user if browser was not configured.
83     }
84   }
85
86   @Override
87   public void refreshGUI()
88   {
89     // appJmolWindow.repaint();
90     appJmolWindow.updateTitleAndMenus();
91   }
92
93   public void updateColours(Object source)
94   {
95     AlignmentPanel ap = (AlignmentPanel) source;
96     if (appJmolWindow.ap.alignFrame.getCurrentView() != ap.av)
97       return;
98
99     colourBySequence(ap.av.getShowSequenceFeatures(), ap.av.alignment);
100   }
101
102   public void notifyScriptTermination(String strStatus, int msWalltime)
103   {
104     if (appJmolWindow.scriptWindow != null)
105       appJmolWindow.scriptWindow.notifyScriptTermination(strStatus,
106               msWalltime);
107   }
108
109   public void showUrl(String url)
110   {
111     showUrl(url, "jmol");
112   }
113
114   public void newJmolPopup(boolean translateLocale, String menuName,
115           boolean asPopup)
116   {
117
118     jmolpopup = JmolPopup.newJmolPopup(viewer, translateLocale, menuName,
119             asPopup);
120   }
121
122   /**
123    * add structures and any known sequence associations
124    * 
125    * @returns the pdb entries added to the current set.
126    */
127   private PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
128           SequenceI[][] seq, String[][] chns)
129   {
130     int pe = -1;
131     Vector v = new Vector();
132     Vector rtn = new Vector();
133     for (int i = 0; i < pdbentry.length; i++)
134     {
135       v.addElement(pdbentry[i]);
136     }
137     for (int i = 0; i < pdbe.length; i++)
138     {
139       int r = v.indexOf(pdbe[i]);
140       if (r == -1 || r >= pdbentry.length)
141       {
142         rtn.addElement(new int[]
143         { v.size(), i });
144         v.addElement(pdbe[i]);
145       }
146       else
147       {
148         // just make sure the sequence/chain entries are all up to date
149         addSequenceAndChain(r, seq[i], chns[i]);
150       }
151     }
152     pdbe = new PDBEntry[v.size()];
153     v.copyInto(pdbe);
154     pdbentry = pdbe;
155     if (rtn.size() > 0)
156     {
157       // expand the tied seuqence[] and string[] arrays
158       SequenceI[][] sqs = new SequenceI[pdbentry.length][];
159       String[][] sch = new String[pdbentry.length][];
160       System.arraycopy(sequence, 0, sqs, 0, sequence.length);
161       System.arraycopy(chains, 0, sch, 0, this.chains.length);
162       sequence = sqs;
163       chains = sch;
164       pdbe = new PDBEntry[rtn.size()];
165       for (int r = 0; r < pdbe.length; r++)
166       {
167         int[] stri = ((int[]) rtn.elementAt(r));
168         // record the pdb file as a new addition
169         pdbe[r] = pdbentry[stri[0]];
170         // and add the new sequence/chain entries
171         addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
172       }
173     }
174     else
175     {
176       pdbe = null;
177     }
178     return pdbe;
179   }
180
181   void addSequence(int pe, SequenceI[] seq)
182   {
183     // add sequences to the pe'th pdbentry's seuqence set.
184     addSequenceAndChain(pe, seq, null);
185   }
186
187   private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
188   {
189     if (pe < 0 || pe >= pdbentry.length)
190     {
191       throw new Error(
192               "Implementation error - no corresponding pdbentry (for index "
193                       + pe + ") to add sequences mappings to");
194     }
195     final String nullChain = "TheNullChain";
196     Vector s = new Vector();
197     Vector c = new Vector();
198     if (chains == null)
199     {
200       chains = new String[pdbentry.length][];
201     }
202     if (sequence[pe] != null)
203     {
204       for (int i = 0; i < sequence[pe].length; i++)
205       {
206         s.addElement(sequence[pe][i]);
207         if (chains[pe] != null)
208         {
209           if (i < chains[pe].length)
210           {
211             c.addElement(chains[pe][i]);
212           }
213           else
214           {
215             c.addElement(nullChain);
216           }
217         }
218         else
219         {
220           if (tchain != null && tchain.length > 0)
221           {
222             c.addElement(nullChain);
223           }
224         }
225       }
226     }
227     for (int i = 0; i < seq.length; i++)
228     {
229       if (!s.contains(seq[i]))
230       {
231         s.addElement(seq[i]);
232         if (tchain != null && i < tchain.length)
233         {
234           c.addElement(tchain[i] == null ? nullChain : tchain[i]);
235         }
236       }
237     }
238     SequenceI[] tmp = new SequenceI[s.size()];
239     s.copyInto(tmp);
240     sequence[pe] = tmp;
241     if (c.size() > 0)
242     {
243       String[] tch = new String[c.size()];
244       c.copyInto(tch);
245       for (int i = 0; i < tch.length; i++)
246       {
247         if (tch[i] == nullChain)
248         {
249           tch[i] = null;
250         }
251       }
252       chains[pe] = tch;
253     }
254     else
255     {
256       chains[pe] = null;
257     }
258   }
259
260   public void selectionChanged(BitSet arg0)
261   {
262     // TODO Auto-generated method stub
263
264   }
265
266   public void refreshPdbEntries()
267   {
268     // TODO Auto-generated method stub
269
270   }
271
272   /**
273    * add another pdb entry into the view, with associated sequences and chains
274    * 
275    * @param pdbentry
276    * @param seq
277    * @param chains
278    * @param align
279    *          if true, new structure(s) will be align using associated alignment
280    */
281   public synchronized void addStructure(PDBEntry pdbentry, SequenceI[] seq,
282           String[] chains, final boolean align)
283   {
284     PDBEntry[] pe = addSequenceAndChain(new PDBEntry[]
285     { pdbentry }, new SequenceI[][]
286     { seq }, new String[][]
287     { chains });
288     if (pe != null)
289     {
290       StringBuffer cmd = new StringBuffer();
291       cmd.append("load APPEND");
292       for (int p = 0; p < pe.length; p++)
293       {
294         cmd.append(" \"");
295         cmd.append(pe[p].getFile());
296         cmd.append("\"");
297       }
298       cmd.append("\n");
299       final String command = cmd.toString();
300       cmd = null;
301       new Thread(new Runnable()
302       {
303         public void run()
304         {
305           evalStateCommand(command);
306           if (align)
307           {
308             // may need to wait around until script has finished
309             while (viewer.isScriptExecuting())
310             {
311               try
312               {
313                 Thread.sleep(20);
314               } catch (Exception e)
315               {
316               }
317               ;
318             }
319             superposeStructures(appJmolWindow.ap.av.getAlignment(), -1, null);
320           }
321         }
322       }).start();
323     }
324   }
325
326   /**
327    * add the given sequences to the mapping scope for the given pdb file handle
328    * 
329    * @param pdbFile
330    *          - pdbFile identifier
331    * @param seq
332    *          - set of sequences it can be mapped to
333    */
334   public void addSequenceForStructFile(String pdbFile, SequenceI[] seq)
335   {
336     for (int pe = 0; pe < pdbentry.length; pe++)
337     {
338       if (pdbentry[pe].getFile().equals(pdbFile))
339       {
340         addSequence(pe, seq);
341       }
342     }
343   }
344
345 }