added
[jalview.git] / src / jalview / gui / AppJmol.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer
3  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.gui;
20
21 import java.util.regex.*;
22 import java.util.*;
23 import java.awt.*;
24 import javax.swing.*;
25 import javax.swing.event.*;
26 import java.awt.event.*;
27 import java.io.*;
28
29 import jalview.jbgui.GStructureViewer;
30 import jalview.datamodel.*;
31 import jalview.gui.*;
32 import jalview.structure.*;
33 import jalview.datamodel.PDBEntry;
34 import jalview.io.*;
35 import jalview.schemes.*;
36
37 import org.jmol.api.*;
38 import org.jmol.adapter.smarter.SmarterJmolAdapter;
39 import org.jmol.popup.*;
40
41
42 public class AppJmol
43     extends GStructureViewer
44     implements StructureListener, JmolStatusListener, Runnable
45
46 {
47   JmolViewer viewer;
48   JmolPopup jmolpopup;
49   ScriptWindow scriptWindow;
50   PDBEntry pdbentry;
51   SequenceI[] sequence;
52   String [] chains;
53   StructureSelectionManager ssm;
54   JSplitPane splitPane;
55   RenderPanel renderPanel;
56   AlignmentPanel ap;
57   String fileLoadingError;
58   boolean colourBySequence = true;
59   boolean loadingFromArchive = false;
60   Vector atomsPicked = new Vector();
61
62   public AppJmol(String file, String id,
63                  SequenceI[] seq,
64                  AlignmentPanel ap,
65                  String loadStatus,
66                  Rectangle bounds)
67   {
68     loadingFromArchive = true;
69     pdbentry = new PDBEntry();
70     pdbentry.setFile(file);
71     pdbentry.setId(id);
72     this.chains = chains;
73     this.sequence = seq;
74     this.ap = ap;
75     this.setBounds(bounds);
76
77     colourBySequence = false;
78     seqColour.setSelected(false);
79
80     jalview.gui.Desktop.addInternalFrame(this, "Loading File",
81                                          bounds.width,bounds.height);
82
83     initJmol(loadStatus);
84
85     this.addInternalFrameListener(new InternalFrameAdapter()
86     {
87       public void internalFrameClosing(InternalFrameEvent internalFrameEvent)
88       {
89         closeViewer();
90       }
91     });
92   }
93
94 public synchronized void addSequence(SequenceI [] seq)
95    {
96     Vector v = new Vector();
97      for(int i=0; i<sequence.length; i++)
98        v.addElement(sequence[i]);
99
100      for(int i=0; i<seq.length; i++)
101       if(!v.contains(seq[i]))
102           v.addElement(seq[i]);
103
104      SequenceI [] tmp = new SequenceI[v.size()];
105      v.copyInto(tmp);
106      sequence = tmp;
107    }
108
109   public AppJmol(PDBEntry pdbentry, SequenceI[] seq, String [] chains, AlignmentPanel ap)
110   {
111     //////////////////////////////////
112     //Is the pdb file already loaded?
113     String alreadyMapped = StructureSelectionManager
114         .getStructureSelectionManager()
115         .alreadyMappedToFile(pdbentry.getId());
116
117     if (alreadyMapped != null)
118     {
119       int option = JOptionPane.showInternalConfirmDialog(Desktop.desktop,
120           pdbentry.getId() + " is already displayed."
121           + "\nDo you want to map sequences to the visible structure?",
122           "Map Sequences to Visible Window: " + pdbentry.getId(),
123           JOptionPane.YES_NO_OPTION);
124
125       if (option == JOptionPane.YES_OPTION)
126       {
127         StructureSelectionManager.getStructureSelectionManager()
128             .setMapping(seq, chains, alreadyMapped, AppletFormatAdapter.FILE);
129         if (ap.seqPanel.seqCanvas.fr!=null) {
130           ap.seqPanel.seqCanvas.fr.featuresAdded();
131           ap.paintAlignment(true);
132         }
133
134         //Now this AppJmol is mapped to new sequences. We must add them to
135         // the exisiting array
136         JInternalFrame [] frames = Desktop.instance.getAllFrames();
137
138         for(int i=0; i<frames.length; i++)
139         {
140           if(frames[i] instanceof AppJmol)
141           {
142            AppJmol topJmol = ((AppJmol)frames[i]);
143            if(topJmol.pdbentry.getFile().equals(alreadyMapped))
144            {
145              topJmol.addSequence(seq);
146              break;
147            }
148           }
149         }
150
151         return;
152       }
153     }
154     ///////////////////////////////////
155
156     this.ap = ap;
157     this.pdbentry = pdbentry;
158     this.sequence = seq;
159
160     jalview.gui.Desktop.addInternalFrame(this, "Loading File", 400, 400);
161
162     if (pdbentry.getFile() != null)
163     {
164       initJmol("load \""+pdbentry.getFile()+"\"");
165     }
166     else
167     {
168       Thread worker = new Thread(this);
169       worker.start();
170     }
171
172     this.addInternalFrameListener(new InternalFrameAdapter()
173     {
174       public void internalFrameClosing(InternalFrameEvent internalFrameEvent)
175       {
176         closeViewer();
177       }
178     });
179   }
180
181
182   void initJmol(String command)
183   {
184     renderPanel = new RenderPanel();
185
186     this.getContentPane().add(renderPanel, java.awt.BorderLayout.CENTER);
187
188     StringBuffer title = new StringBuffer(sequence[0].getName() + ":" +
189                                           pdbentry.getId());
190
191     if (pdbentry.getProperty() != null)
192     {
193       if (pdbentry.getProperty().get("method") != null)
194       {
195         title.append(" Method: ");
196         title.append(pdbentry.getProperty().get("method"));
197       }
198       if (pdbentry.getProperty().get("chains") != null)
199       {
200         title.append(" Chain:");
201         title.append(pdbentry.getProperty().get("chains"));
202       }
203     }
204
205     this.setTitle(title.toString());
206
207     viewer = org.jmol.api.JmolViewer.allocateViewer(renderPanel,
208         new SmarterJmolAdapter());
209
210
211     viewer.setAppletContext("", null, null, "");
212
213     viewer.setJmolStatusListener(this);
214
215     jmolpopup = JmolPopup.newJmolPopup(viewer);
216
217     viewer.evalStringQuiet(command);
218   }
219
220
221   void setChainMenuItems(Vector chains)
222   {
223     chainMenu.removeAll();
224
225     JMenuItem menuItem = new JMenuItem("All");
226     menuItem.addActionListener(new ActionListener()
227         {
228           public void actionPerformed(ActionEvent evt)
229           {
230             allChainsSelected = true;
231             for(int i=0; i<chainMenu.getItemCount(); i++)
232             {
233               if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
234                 ( (JCheckBoxMenuItem) chainMenu.getItem(i)).setSelected(true);
235             }
236             centerViewer();
237             allChainsSelected = false;
238           }
239         });
240
241     chainMenu.add(menuItem);
242
243     for (int c = 0; c < chains.size(); c++)
244     {
245       menuItem = new JCheckBoxMenuItem(chains.elementAt(c).toString(), true);
246       menuItem.addItemListener(new ItemListener()
247       {
248         public void itemStateChanged(ItemEvent evt)
249         {
250           if (!allChainsSelected)
251             centerViewer();
252         }
253       });
254
255       chainMenu.add(menuItem);
256     }
257   }
258
259   boolean allChainsSelected = false;
260   void centerViewer()
261   {
262     StringBuffer cmd = new StringBuffer();
263     for(int i=0; i<chainMenu.getItemCount(); i++)
264     {
265       if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
266       {
267        JCheckBoxMenuItem item = (JCheckBoxMenuItem) chainMenu.getItem(i);
268        if(item.isSelected())
269          cmd.append(":"+item.getText()+" or ");
270       }
271     }
272
273     if (cmd.length() > 0)
274       cmd.setLength(cmd.length() - 4);
275
276     viewer.evalStringQuiet("select *;restrict "
277                       +cmd+";cartoon;center "+cmd);
278   }
279
280   void closeViewer()
281   {
282     viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
283     viewer.evalStringQuiet("zap");
284     viewer.setJmolStatusListener(null);
285     viewer = null;
286
287     //We'll need to find out what other
288     // listeners need to be shut down in Jmol
289     StructureSelectionManager
290         .getStructureSelectionManager()
291         .removeStructureViewerListener(this, pdbentry.getFile());
292   }
293
294   public void run()
295   {
296     try
297     {
298       EBIFetchClient ebi = new EBIFetchClient();
299       String query = "pdb:" + pdbentry.getId();
300       pdbentry.setFile(ebi.fetchDataAsFile(query, "default", "raw")
301                        .getAbsolutePath());
302       initJmol("load "+pdbentry.getFile());
303     }
304     catch (Exception ex)
305     {
306       ex.printStackTrace();
307     }
308   }
309
310   public void pdbFile_actionPerformed(ActionEvent actionEvent)
311   {
312     JalviewFileChooser chooser = new JalviewFileChooser(
313         jalview.bin.Cache.getProperty(
314             "LAST_DIRECTORY"));
315
316     chooser.setFileView(new JalviewFileView());
317     chooser.setDialogTitle("Save PDB File");
318     chooser.setToolTipText("Save");
319
320     int value = chooser.showSaveDialog(this);
321
322     if (value == JalviewFileChooser.APPROVE_OPTION)
323     {
324       try
325       {
326         BufferedReader in = new BufferedReader(new FileReader(pdbentry.getFile()));
327         File outFile = chooser.getSelectedFile();
328
329         PrintWriter out = new PrintWriter(new FileOutputStream(outFile));
330         String data;
331         while ( (data = in.readLine()) != null)
332         {
333           if (
334               ! (data.indexOf("<PRE>") > -1 || data.indexOf("</PRE>") > -1)
335               )
336           {
337             out.println(data);
338           }
339         }
340         out.close();
341       }
342       catch (Exception ex)
343       {
344         ex.printStackTrace();
345       }
346     }
347   }
348
349   public void viewMapping_actionPerformed(ActionEvent actionEvent)
350   {
351     jalview.gui.CutAndPasteTransfer cap = new jalview.gui.CutAndPasteTransfer();
352     jalview.gui.Desktop.addInternalFrame(cap, "PDB - Sequence Mapping", 550,
353                                          600);
354     cap.setText(
355         StructureSelectionManager.getStructureSelectionManager().printMapping(
356             pdbentry.getFile())
357         );
358   }
359
360   /**
361    * DOCUMENT ME!
362    *
363    * @param e DOCUMENT ME!
364    */
365   public void eps_actionPerformed(ActionEvent e)
366   {
367     makePDBImage(jalview.util.ImageMaker.EPS);
368   }
369
370   /**
371    * DOCUMENT ME!
372    *
373    * @param e DOCUMENT ME!
374    */
375   public void png_actionPerformed(ActionEvent e)
376   {
377     makePDBImage(jalview.util.ImageMaker.PNG);
378   }
379
380   void makePDBImage(int type)
381   {
382     int width = getWidth();
383     int height = getHeight();
384
385     jalview.util.ImageMaker im;
386
387     if (type == jalview.util.ImageMaker.PNG)
388     {
389       im = new jalview.util.ImageMaker(this,
390                                        jalview.util.ImageMaker.PNG,
391                                        "Make PNG image from view",
392                                        width, height,
393                                        null, null);
394     }
395     else
396     {
397       im = new jalview.util.ImageMaker(this,
398                                        jalview.util.ImageMaker.EPS,
399                                        "Make EPS file from view",
400                                        width, height,
401                                        null, this.getTitle());
402     }
403
404     if (im.getGraphics() != null)
405     {
406       Rectangle rect = new Rectangle(width, height);
407       viewer.renderScreenImage(im.getGraphics(),
408                                rect.getSize(), rect);
409       im.writeImage();
410     }
411   }
412
413
414   public void seqColour_actionPerformed(ActionEvent actionEvent)
415   {
416     colourBySequence = seqColour.isSelected();
417     colourBySequence(ap.alignFrame.alignPanel);
418   }
419
420   public void chainColour_actionPerformed(ActionEvent actionEvent)
421   {
422     colourBySequence = false;
423     seqColour.setSelected(false);
424     viewer.evalStringQuiet("select *;color chain");
425   }
426
427   public void chargeColour_actionPerformed(ActionEvent actionEvent)
428   {
429     colourBySequence = false;
430     seqColour.setSelected(false);
431     viewer.evalStringQuiet("select *;color white;select ASP,GLU;color red;"
432                       +"select LYS,ARG;color blue;select CYS;color yellow");
433   }
434
435   public void zappoColour_actionPerformed(ActionEvent actionEvent)
436   {
437     setJalviewColourScheme(new ZappoColourScheme());
438   }
439
440   public void taylorColour_actionPerformed(ActionEvent actionEvent)
441   {
442     setJalviewColourScheme(new TaylorColourScheme());
443   }
444
445   public void hydroColour_actionPerformed(ActionEvent actionEvent)
446   {
447     setJalviewColourScheme(new HydrophobicColourScheme());
448   }
449
450   public void helixColour_actionPerformed(ActionEvent actionEvent)
451   {
452     setJalviewColourScheme(new HelixColourScheme());
453   }
454
455   public void strandColour_actionPerformed(ActionEvent actionEvent)
456   {
457     setJalviewColourScheme(new StrandColourScheme());
458   }
459
460   public void turnColour_actionPerformed(ActionEvent actionEvent)
461   {
462     setJalviewColourScheme(new TurnColourScheme());
463   }
464
465   public void buriedColour_actionPerformed(ActionEvent actionEvent)
466   {
467     setJalviewColourScheme(new BuriedColourScheme());
468   }
469
470   public void setJalviewColourScheme(ColourSchemeI cs)
471   {
472     colourBySequence = false;
473     seqColour.setSelected(false);
474
475     if(cs==null)
476       return;
477
478     String res;
479     int index;
480     Color col;
481
482     Enumeration en = ResidueProperties.aa3Hash.keys();
483     StringBuffer command = new StringBuffer("select *;color white;");
484     while(en.hasMoreElements())
485     {
486       res = en.nextElement().toString();
487       index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
488       if(index>20)
489         continue;
490
491       col = cs.findColour(ResidueProperties.aa[index].charAt(0));
492
493       command.append("select "+res+";color["
494                         + col.getRed() + ","
495                         + col.getGreen() + ","
496                         + col.getBlue() + "];");
497     }
498
499     viewer.evalStringQuiet(command.toString());
500   }
501
502   public void userColour_actionPerformed(ActionEvent actionEvent)
503   {
504     new UserDefinedColours(this, null);
505   }
506
507   public void backGround_actionPerformed(ActionEvent actionEvent)
508   {
509     java.awt.Color col = JColorChooser.showDialog(this,
510                                                   "Select Background Colour",
511                                                   null);
512
513     if (col != null)
514     {
515       viewer.evalStringQuiet("background ["
516                         + col.getRed() + ","
517                         + col.getGreen() + ","
518                         + col.getBlue() + "];");
519     }
520   }
521
522
523   public void jmolHelp_actionPerformed(ActionEvent actionEvent)
524   {
525        try{
526          jalview.util.BrowserLauncher.openURL(
527              "http://jmol.sourceforge.net/docs/JmolUserGuide/");
528        }catch(Exception ex){}
529    }
530
531
532   //////////////////////////////////
533   ///StructureListener
534   public String getPdbFile()
535   {
536     return pdbentry.getFile();
537   }
538
539   Pattern pattern = Pattern.compile(
540       "\\[(.*)\\]([0-9]+)(:[a-zA-Z]*)?\\.([a-zA-Z]+)(/[0-9]*)?"
541       );
542
543   String lastMessage;
544   public void mouseOverStructure(int atomIndex, String strInfo)
545   {
546     Matcher matcher = pattern.matcher(strInfo);
547     matcher.find();
548     matcher.group(1);
549     int pdbResNum = Integer.parseInt(matcher.group(2));
550     String chainId = matcher.group(3);
551
552     if (chainId != null)
553       chainId = chainId.substring(1, chainId.length());
554     else
555     {
556       chainId = " ";
557     }
558
559     if (lastMessage == null || !lastMessage.equals(strInfo))
560     {
561       ssm.mouseOverStructure(pdbResNum, chainId, pdbentry.getFile());
562     }
563     lastMessage = strInfo;
564   }
565
566   StringBuffer resetLastRes = new StringBuffer();
567   StringBuffer eval = new StringBuffer();
568
569   public void highlightAtom(int atomIndex, int pdbResNum, String chain, String pdbfile)
570   {
571     if (!pdbfile.equals(pdbentry.getFile()))
572       return;
573
574     if (resetLastRes.length() > 0)
575     {
576       viewer.evalStringQuiet(resetLastRes.toString());
577     }
578
579     eval.setLength(0);
580     eval.append("select " + pdbResNum);
581
582     resetLastRes.setLength(0);
583     resetLastRes.append("select " + pdbResNum);
584
585     if (!chain.equals(" "))
586     {
587       eval.append(":" + chain);
588       resetLastRes.append(":" + chain);
589     }
590
591     eval.append(";color gold;wireframe 100");
592
593     Color col = new Color(viewer.getAtomArgb(atomIndex));
594
595     resetLastRes.append(";color["
596                         + col.getRed() + ","
597                         + col.getGreen() + ","
598                         + col.getBlue() + "];wireframe 0");
599
600     viewer.evalStringQuiet(eval.toString());
601
602   }
603
604   public Color getColour(int atomIndex, int pdbResNum, String chain, String pdbfile)
605   {
606     if (!pdbfile.equals(pdbentry.getFile()))
607       return null;
608
609     return new Color(viewer.getAtomArgb(atomIndex));
610   }
611
612   public void updateColours(Object source)
613   {
614     colourBySequence( (AlignmentPanel) source);
615   }
616
617
618 //End StructureListener
619 ////////////////////////////
620
621   String lastCommand;
622   FeatureRenderer fr=null;
623   public void colourBySequence(AlignmentPanel sourceap)
624   {
625     this.ap = sourceap;
626
627     if(!colourBySequence || ap.alignFrame.getCurrentView()!=ap.av)
628       return;
629
630     StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());
631
632     if (mapping.length < 1)
633      return;
634
635
636     SequenceRenderer sr = new SequenceRenderer(ap.av);
637
638     boolean showFeatures = false;
639
640     if (ap.av.showSequenceFeatures)
641     {
642       showFeatures = true;
643       if (fr == null)
644       {
645         fr = new jalview.gui.FeatureRenderer(ap);
646       }
647
648       fr.transferSettings(ap.seqPanel.seqCanvas.getFeatureRenderer());
649     }
650
651     StringBuffer command = new StringBuffer();
652
653     int lastPos = -1;
654     for (int s = 0; s < sequence.length; s++)
655     {
656       for (int m = 0; m < mapping.length; m++)
657       {
658         System.out.println(mapping[m].getSequence().getName()+" "+sequence[s].getName()+" "
659         +((mapping[m].getSequence() == sequence[s])
660           +" "+(ap.av.alignment.findIndex(sequence[s]))));
661
662                            if (mapping[m].getSequence() == sequence[s]
663             && ap.av.alignment.findIndex(sequence[s])>-1)
664         {
665           for (int r = 0; r < sequence[s].getLength(); r++)
666           {
667             int pos = mapping[m].getPDBResNum(
668                 sequence[s].findPosition(r));
669
670             if (pos < 1 || pos==lastPos)
671               continue;
672
673             lastPos = pos;
674
675             Color col = sr.getResidueBoxColour(sequence[s], r);
676
677             if (showFeatures)
678               col = fr.findFeatureColour(col, sequence[s], r);
679
680             if (command.toString().endsWith(":" + mapping[m].getChain()+
681                                             ";color["
682                                             + col.getRed() + ","
683                                             + col.getGreen() + ","
684                                             + col.getBlue() + "]"))
685             {
686               command = condenseCommand(command, pos);
687               continue;
688             }
689
690             command.append(";select " + pos);
691
692             if (!mapping[m].getChain().equals(" "))
693             {
694               command.append(":" + mapping[m].getChain());
695             }
696
697             command.append(";color["
698                              + col.getRed() + ","
699                              + col.getGreen() + ","
700                              + col.getBlue() + "]");
701
702           }
703           break;
704         }
705       }
706     }
707
708     if (lastCommand == null || !lastCommand.equals(command.toString()))
709     {
710       viewer.evalStringQuiet(command.toString());
711     }
712     lastCommand = command.toString();
713   }
714
715   StringBuffer condenseCommand(StringBuffer command, int pos)
716   {
717     StringBuffer sb = new StringBuffer(command.substring(0, command.lastIndexOf("select")+7));
718
719     command.delete(0, sb.length());
720
721     String start;
722
723     if (command.indexOf("-") > -1)
724     {
725       start = command.substring(0,command.indexOf("-"));
726     }
727     else
728     {
729       start = command.substring(0, command.indexOf(":"));
730     }
731
732     sb.append(start+"-"+pos+command.substring(command.indexOf(":")));
733
734     return sb;
735   }
736
737   /////////////////////////////////
738   //JmolStatusListener
739
740   public String eval(String strEval)
741   {
742    // System.out.println(strEval);
743    //"# 'eval' is implemented only for the applet.";
744     return null;
745   }
746
747   public void createImage(String file, String type, int quality)
748   {
749     System.out.println("JMOL CREATE IMAGE");
750   }
751
752   public void setCallbackFunction(String callbackType,
753                                   String callbackFunction)
754   {}
755
756   public void notifyFileLoaded(String fullPathName, String fileName,
757                                String modelName, Object clientFile,
758                                String errorMsg)
759   {
760     if(errorMsg!=null)
761     {
762       fileLoadingError = errorMsg;
763       repaint();
764       return;
765     }
766
767     fileLoadingError = null;
768
769     if (fileName != null)
770     {
771
772       //FILE LOADED OK
773       ssm = StructureSelectionManager.getStructureSelectionManager();
774       MCview.PDBfile pdbFile = ssm.setMapping(sequence,chains,pdbentry.getFile(), AppletFormatAdapter.FILE);
775       ssm.addStructureViewerListener(this);
776       Vector chains = new Vector();
777       for(int i=0; i<pdbFile.chains.size(); i++)
778       {
779         chains.addElement(((MCview.PDBChain)pdbFile.chains.elementAt(i)).id);
780       }
781       setChainMenuItems(chains);
782
783       jmolpopup.updateComputedMenus();
784
785       if(!loadingFromArchive)
786       {
787         viewer.evalStringQuiet(
788              "select backbone;restrict;cartoon;wireframe off;spacefill off");
789
790         colourBySequence(ap);
791       }
792       if (fr!=null)
793         fr.featuresAdded();
794
795       loadingFromArchive = false;
796     }
797     else
798       return;
799   }
800
801   public void notifyFrameChanged(int frameNo)
802   {
803     boolean isAnimationRunning = (frameNo <= -2);
804   }
805
806   public void notifyScriptStart(String statusMessage, String additionalInfo)
807   {}
808
809   public void sendConsoleEcho(String strEcho)
810   {
811     if (scriptWindow != null)
812       scriptWindow.sendConsoleEcho(strEcho);
813   }
814
815   public void sendConsoleMessage(String strStatus)
816   {
817     if (scriptWindow != null)
818       scriptWindow.sendConsoleMessage(strStatus);
819   }
820
821   public void notifyScriptTermination(String strStatus, int msWalltime)
822   {
823     if (scriptWindow != null)
824       scriptWindow.notifyScriptTermination(strStatus, msWalltime);
825   }
826
827   public void handlePopupMenu(int x, int y)
828   {
829     jmolpopup.show(x, y);
830   }
831
832   public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
833   {
834     notifyAtomPicked(iatom, strMeasure);
835   }
836
837   public void notifyNewDefaultModeMeasurement(int count, String strInfo)
838   {}
839
840   public void notifyAtomPicked(int atomIndex, String strInfo)
841   {
842     Matcher matcher = pattern.matcher(strInfo);
843     matcher.find();
844
845     matcher.group(1);
846     String resnum = new String(matcher.group(2));
847     String chainId = matcher.group(3);
848
849     String picked = resnum;
850
851     if (chainId != null)
852       picked+=(":"+chainId.substring(1, chainId.length()));
853
854     picked+=".C";
855
856     if (!atomsPicked.contains(picked))
857     {
858       if(chainId!=null)
859       viewer.evalString("select "+picked+";label %n %r:%c");
860     else
861       viewer.evalString("select "+picked+";label %n %r");
862       atomsPicked.addElement(picked);
863     }
864     else
865     {
866       viewer.evalString("select "+picked+";label off");
867       atomsPicked.removeElement(picked);
868     }
869
870     if (scriptWindow != null)
871     {
872       scriptWindow.sendConsoleMessage(strInfo);
873       scriptWindow.sendConsoleMessage("\n");
874     }
875   }
876
877   public void notifyAtomHovered(int atomIndex, String strInfo)
878   {
879     mouseOverStructure(atomIndex, strInfo);
880   }
881
882   public void sendSyncScript(String script, String appletName)
883   {}
884
885   public void showUrl(String url)
886   {}
887
888   public void showConsole(boolean showConsole)
889   {
890     if (scriptWindow == null)
891       scriptWindow = new ScriptWindow(this);
892
893     if(showConsole)
894     {
895       if(splitPane==null)
896       {
897         splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
898         splitPane.setTopComponent(renderPanel);
899         splitPane.setBottomComponent(scriptWindow);
900         this.getContentPane().add(splitPane, BorderLayout.CENTER);
901       }
902
903       splitPane.setDividerLocation(getHeight()-200);
904       splitPane.validate();
905     }
906     else
907     {
908       if (splitPane != null)
909         splitPane.setVisible(false);
910
911       splitPane = null;
912
913       this.getContentPane().add(renderPanel, BorderLayout.CENTER);
914     }
915
916     validate();
917   }
918
919   public float functionXY(String functionName, int x, int y)
920   {
921     return 0;
922   }
923
924   ///End JmolStatusListener
925   ///////////////////////////////
926
927
928   class RenderPanel
929       extends JPanel
930   {
931     final Dimension currentSize = new Dimension();
932     final Rectangle rectClip = new Rectangle();
933
934     public void paintComponent(Graphics g)
935     {
936       getSize(currentSize);
937       g.getClipBounds(rectClip);
938
939       if (viewer == null)
940       {
941         g.setColor(Color.black);
942         g.fillRect(0, 0, currentSize.width, currentSize.height);
943         g.setColor(Color.white);
944         g.setFont(new Font("Verdana", Font.BOLD, 14));
945         g.drawString("Retrieving PDB data....", 20, currentSize.height / 2);
946       }
947       else if(fileLoadingError!=null)
948       {
949         g.setColor(Color.black);
950         g.fillRect(0, 0, currentSize.width, currentSize.height);
951         g.setColor(Color.white);
952         g.setFont(new Font("Verdana", Font.BOLD, 14));
953         g.drawString("Error loading file..." + pdbentry.getId(), 20,
954                      currentSize.height / 2);
955       }
956       else
957       {
958         viewer.renderScreenImage(g, currentSize, rectClip);
959       }
960     }
961   }
962
963 }