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