DONT SET PICKING LABEL
[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     lastCommand = null;
417     colourBySequence = seqColour.isSelected();
418     colourBySequence(ap.alignFrame.alignPanel);
419   }
420
421   public void chainColour_actionPerformed(ActionEvent actionEvent)
422   {
423     colourBySequence = false;
424     seqColour.setSelected(false);
425     viewer.evalStringQuiet("select *;color chain");
426   }
427
428   public void chargeColour_actionPerformed(ActionEvent actionEvent)
429   {
430     colourBySequence = false;
431     seqColour.setSelected(false);
432     viewer.evalStringQuiet("select *;color white;select ASP,GLU;color red;"
433                       +"select LYS,ARG;color blue;select CYS;color yellow");
434   }
435
436   public void zappoColour_actionPerformed(ActionEvent actionEvent)
437   {
438     setJalviewColourScheme(new ZappoColourScheme());
439   }
440
441   public void taylorColour_actionPerformed(ActionEvent actionEvent)
442   {
443     setJalviewColourScheme(new TaylorColourScheme());
444   }
445
446   public void hydroColour_actionPerformed(ActionEvent actionEvent)
447   {
448     setJalviewColourScheme(new HydrophobicColourScheme());
449   }
450
451   public void helixColour_actionPerformed(ActionEvent actionEvent)
452   {
453     setJalviewColourScheme(new HelixColourScheme());
454   }
455
456   public void strandColour_actionPerformed(ActionEvent actionEvent)
457   {
458     setJalviewColourScheme(new StrandColourScheme());
459   }
460
461   public void turnColour_actionPerformed(ActionEvent actionEvent)
462   {
463     setJalviewColourScheme(new TurnColourScheme());
464   }
465
466   public void buriedColour_actionPerformed(ActionEvent actionEvent)
467   {
468     setJalviewColourScheme(new BuriedColourScheme());
469   }
470
471   public void setJalviewColourScheme(ColourSchemeI cs)
472   {
473     colourBySequence = false;
474     seqColour.setSelected(false);
475
476     if(cs==null)
477       return;
478
479     String res;
480     int index;
481     Color col;
482
483     Enumeration en = ResidueProperties.aa3Hash.keys();
484     StringBuffer command = new StringBuffer("select *;color white;");
485     while(en.hasMoreElements())
486     {
487       res = en.nextElement().toString();
488       index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
489       if(index>20)
490         continue;
491
492       col = cs.findColour(ResidueProperties.aa[index].charAt(0));
493
494       command.append("select "+res+";color["
495                         + col.getRed() + ","
496                         + col.getGreen() + ","
497                         + col.getBlue() + "];");
498     }
499
500     viewer.evalStringQuiet(command.toString());
501   }
502
503   public void userColour_actionPerformed(ActionEvent actionEvent)
504   {
505     new UserDefinedColours(this, null);
506   }
507
508   public void backGround_actionPerformed(ActionEvent actionEvent)
509   {
510     java.awt.Color col = JColorChooser.showDialog(this,
511                                                   "Select Background Colour",
512                                                   null);
513
514     if (col != null)
515     {
516       viewer.evalStringQuiet("background ["
517                         + col.getRed() + ","
518                         + col.getGreen() + ","
519                         + col.getBlue() + "];");
520     }
521   }
522
523
524   public void jmolHelp_actionPerformed(ActionEvent actionEvent)
525   {
526        try{
527          jalview.util.BrowserLauncher.openURL(
528              "http://jmol.sourceforge.net/docs/JmolUserGuide/");
529        }catch(Exception ex){}
530    }
531
532
533   //////////////////////////////////
534   ///StructureListener
535   public String getPdbFile()
536   {
537     return pdbentry.getFile();
538   }
539
540   Pattern pattern = Pattern.compile(
541       "\\[(.*)\\]([0-9]+)(:[a-zA-Z]*)?\\.([a-zA-Z]+)(/[0-9]*)?"
542       );
543
544   String lastMessage;
545   public void mouseOverStructure(int atomIndex, String strInfo)
546   {
547     Matcher matcher = pattern.matcher(strInfo);
548     matcher.find();
549     matcher.group(1);
550     int pdbResNum = Integer.parseInt(matcher.group(2));
551     String chainId = matcher.group(3);
552
553     if (chainId != null)
554       chainId = chainId.substring(1, chainId.length());
555     else
556     {
557       chainId = " ";
558     }
559
560     if (lastMessage == null || !lastMessage.equals(strInfo))
561     {
562       ssm.mouseOverStructure(pdbResNum, chainId, pdbentry.getFile());
563     }
564     lastMessage = strInfo;
565   }
566
567   StringBuffer resetLastRes = new StringBuffer();
568   StringBuffer eval = new StringBuffer();
569
570   public void highlightAtom(int atomIndex, int pdbResNum, String chain, String pdbfile)
571   {
572     if (!pdbfile.equals(pdbentry.getFile()))
573       return;
574
575     if (resetLastRes.length() > 0)
576     {
577       viewer.evalStringQuiet(resetLastRes.toString());
578     }
579
580     eval.setLength(0);
581     eval.append("select " + pdbResNum);
582
583     resetLastRes.setLength(0);
584     resetLastRes.append("select " + pdbResNum);
585
586     if (!chain.equals(" "))
587     {
588       eval.append(":" + chain);
589       resetLastRes.append(":" + chain);
590     }
591
592     eval.append(";wireframe 100;"+eval.toString()+".CA;");
593
594     resetLastRes.append(";wireframe 0;"+resetLastRes.toString()+".CA;spacefill 0;");
595
596     eval.append("spacefill 200;select none");
597
598     viewer.evalStringQuiet(eval.toString());
599   }
600
601   public Color getColour(int atomIndex, int pdbResNum, String chain, String pdbfile)
602   {
603     if (!pdbfile.equals(pdbentry.getFile()))
604       return null;
605
606     return new Color(viewer.getAtomArgb(atomIndex));
607   }
608
609   public void updateColours(Object source)
610   {
611     colourBySequence( (AlignmentPanel) source);
612   }
613
614
615 //End StructureListener
616 ////////////////////////////
617
618   String lastCommand;
619   FeatureRenderer fr=null;
620   public void colourBySequence(AlignmentPanel sourceap)
621   {
622     this.ap = sourceap;
623
624     if(!colourBySequence || ap.alignFrame.getCurrentView()!=ap.av)
625       return;
626
627     StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());
628
629     if (mapping.length < 1)
630      return;
631
632
633     SequenceRenderer sr = new SequenceRenderer(ap.av);
634
635     boolean showFeatures = false;
636
637     if (ap.av.showSequenceFeatures)
638     {
639       showFeatures = true;
640       if (fr == null)
641       {
642         fr = new jalview.gui.FeatureRenderer(ap);
643       }
644
645       fr.transferSettings(ap.seqPanel.seqCanvas.getFeatureRenderer());
646     }
647
648     StringBuffer command = new StringBuffer();
649
650     int lastPos = -1;
651     for (int s = 0; s < sequence.length; s++)
652     {
653       for (int m = 0; m < mapping.length; m++)
654       {
655         if (mapping[m].getSequence() == sequence[s]
656             && ap.av.alignment.findIndex(sequence[s])>-1)
657         {
658           for (int r = 0; r < sequence[s].getLength(); r++)
659           {
660             int pos = mapping[m].getPDBResNum(
661                 sequence[s].findPosition(r));
662
663             if (pos < 1 || pos==lastPos)
664               continue;
665
666             lastPos = pos;
667
668             Color col = sr.getResidueBoxColour(sequence[s], r);
669
670             if (showFeatures)
671               col = fr.findFeatureColour(col, sequence[s], r);
672
673             if (command.toString().endsWith(":" + mapping[m].getChain()+
674                                             ";color["
675                                             + col.getRed() + ","
676                                             + col.getGreen() + ","
677                                             + col.getBlue() + "]"))
678             {
679               command = condenseCommand(command, pos);
680               continue;
681             }
682
683             command.append(";select " + pos);
684
685             if (!mapping[m].getChain().equals(" "))
686             {
687               command.append(":" + mapping[m].getChain());
688             }
689
690             command.append(";color["
691                              + col.getRed() + ","
692                              + col.getGreen() + ","
693                              + col.getBlue() + "]");
694
695           }
696           break;
697         }
698       }
699     }
700
701     if (lastCommand == null || !lastCommand.equals(command.toString()))
702     {
703       viewer.evalStringQuiet(command.toString());
704     }
705     lastCommand = command.toString();
706   }
707
708   StringBuffer condenseCommand(StringBuffer command, int pos)
709   {
710     StringBuffer sb = new StringBuffer(command.substring(0, command.lastIndexOf("select")+7));
711
712     command.delete(0, sb.length());
713
714     String start;
715
716     if (command.indexOf("-") > -1)
717     {
718       start = command.substring(0,command.indexOf("-"));
719     }
720     else
721     {
722       start = command.substring(0, command.indexOf(":"));
723     }
724
725     sb.append(start+"-"+pos+command.substring(command.indexOf(":")));
726
727     return sb;
728   }
729
730   /////////////////////////////////
731   //JmolStatusListener
732
733   public String eval(String strEval)
734   {
735    // System.out.println(strEval);
736    //"# 'eval' is implemented only for the applet.";
737     return null;
738   }
739
740   public void createImage(String file, String type, int quality)
741   {
742     System.out.println("JMOL CREATE IMAGE");
743   }
744
745   public void setCallbackFunction(String callbackType,
746                                   String callbackFunction)
747   {}
748
749   public void notifyFileLoaded(String fullPathName, String fileName,
750                                String modelName, Object clientFile,
751                                String errorMsg)
752   {
753     if(errorMsg!=null)
754     {
755       fileLoadingError = errorMsg;
756       repaint();
757       return;
758     }
759
760     fileLoadingError = null;
761
762     if (fileName != null)
763     {
764
765       //FILE LOADED OK
766       ssm = StructureSelectionManager.getStructureSelectionManager();
767       MCview.PDBfile pdbFile = ssm.setMapping(sequence,chains,pdbentry.getFile(), AppletFormatAdapter.FILE);
768       ssm.addStructureViewerListener(this);
769       Vector chains = new Vector();
770       for(int i=0; i<pdbFile.chains.size(); i++)
771       {
772         chains.addElement(((MCview.PDBChain)pdbFile.chains.elementAt(i)).id);
773       }
774       setChainMenuItems(chains);
775
776       jmolpopup.updateComputedMenus();
777
778       if(!loadingFromArchive)
779       {
780         viewer.evalStringQuiet(
781              "select backbone;restrict;cartoon;wireframe off;spacefill off");
782
783         colourBySequence(ap);
784       }
785       if (fr!=null)
786         fr.featuresAdded();
787
788       loadingFromArchive = false;
789     }
790     else
791       return;
792   }
793
794   public void notifyFrameChanged(int frameNo)
795   {
796     boolean isAnimationRunning = (frameNo <= -2);
797   }
798
799   public void notifyScriptStart(String statusMessage, String additionalInfo)
800   {}
801
802   public void sendConsoleEcho(String strEcho)
803   {
804     if (scriptWindow != null)
805       scriptWindow.sendConsoleEcho(strEcho);
806   }
807
808   public void sendConsoleMessage(String strStatus)
809   {
810     if (scriptWindow != null)
811       scriptWindow.sendConsoleMessage(strStatus);
812   }
813
814   public void notifyScriptTermination(String strStatus, int msWalltime)
815   {
816     if (scriptWindow != null)
817       scriptWindow.notifyScriptTermination(strStatus, msWalltime);
818   }
819
820   public void handlePopupMenu(int x, int y)
821   {
822     jmolpopup.show(x, y);
823   }
824
825   public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
826   {
827     notifyAtomPicked(iatom, strMeasure);
828   }
829
830   public void notifyNewDefaultModeMeasurement(int count, String strInfo)
831   {}
832
833   public void notifyAtomPicked(int atomIndex, String strInfo)
834   {
835     Matcher matcher = pattern.matcher(strInfo);
836     matcher.find();
837
838     matcher.group(1);
839     String resnum = new String(matcher.group(2));
840     String chainId = matcher.group(3);
841
842     String picked = resnum;
843
844     if (chainId != null)
845       picked+=(":"+chainId.substring(1, chainId.length()));
846
847     picked+=".CA";
848
849
850     if (!atomsPicked.contains(picked))
851     {
852       if(chainId!=null)
853       viewer.evalString("select "+picked+";label %n %r:%c");
854     else
855       viewer.evalString("select "+picked+";label %n %r");
856       atomsPicked.addElement(picked);
857     }
858     else
859     {
860       viewer.evalString("select "+picked+";label off");
861       atomsPicked.removeElement(picked);
862     }
863
864     if (scriptWindow != null)
865     {
866       scriptWindow.sendConsoleMessage(strInfo);
867       scriptWindow.sendConsoleMessage("\n");
868     }
869   }
870
871   public void notifyAtomHovered(int atomIndex, String strInfo)
872   {
873     mouseOverStructure(atomIndex, strInfo);
874   }
875
876   public void sendSyncScript(String script, String appletName)
877   {}
878
879   public void showUrl(String url)
880   {}
881
882   public void showConsole(boolean showConsole)
883   {
884     if (scriptWindow == null)
885       scriptWindow = new ScriptWindow(this);
886
887     if(showConsole)
888     {
889       if(splitPane==null)
890       {
891         splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
892         splitPane.setTopComponent(renderPanel);
893         splitPane.setBottomComponent(scriptWindow);
894         this.getContentPane().add(splitPane, BorderLayout.CENTER);
895       }
896
897       splitPane.setDividerLocation(getHeight()-200);
898       splitPane.validate();
899     }
900     else
901     {
902       if (splitPane != null)
903         splitPane.setVisible(false);
904
905       splitPane = null;
906
907       this.getContentPane().add(renderPanel, BorderLayout.CENTER);
908     }
909
910     validate();
911   }
912
913   public float functionXY(String functionName, int x, int y)
914   {
915     return 0;
916   }
917
918   ///End JmolStatusListener
919   ///////////////////////////////
920
921
922   class RenderPanel
923       extends JPanel
924   {
925     final Dimension currentSize = new Dimension();
926     final Rectangle rectClip = new Rectangle();
927
928     public void paintComponent(Graphics g)
929     {
930       getSize(currentSize);
931       g.getClipBounds(rectClip);
932
933       if (viewer == null)
934       {
935         g.setColor(Color.black);
936         g.fillRect(0, 0, currentSize.width, currentSize.height);
937         g.setColor(Color.white);
938         g.setFont(new Font("Verdana", Font.BOLD, 14));
939         g.drawString("Retrieving PDB data....", 20, currentSize.height / 2);
940       }
941       else if(fileLoadingError!=null)
942       {
943         g.setColor(Color.black);
944         g.fillRect(0, 0, currentSize.width, currentSize.height);
945         g.setColor(Color.white);
946         g.setFont(new Font("Verdana", Font.BOLD, 14));
947         g.drawString("Error loading file..." + pdbentry.getId(), 20,
948                      currentSize.height / 2);
949       }
950       else
951       {
952         viewer.renderScreenImage(g, currentSize, rectClip);
953       }
954     }
955   }
956
957 }