001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 * Created on 24.05.2004 021 * @author Andreas Prlic 022 * 023 */ 024package org.biojava.nbio.structure.align.gui.jmol; 025 026import org.biojava.nbio.structure.*; 027import org.biojava.nbio.structure.align.gui.AlignmentGui; 028import org.biojava.nbio.structure.align.gui.DisplayAFP; 029import org.biojava.nbio.structure.align.gui.MenuCreator; 030import org.biojava.nbio.structure.align.model.AFPChain; 031import org.biojava.nbio.structure.align.model.AfpChainWriter; 032import org.biojava.nbio.structure.align.util.AtomCache; 033import org.biojava.nbio.structure.align.util.ResourceManager; 034import org.biojava.nbio.structure.align.util.UserConfiguration; 035import org.biojava.nbio.structure.align.webstart.AligUIManager; 036import org.biojava.nbio.structure.gui.util.color.ColorUtils; 037import org.biojava.nbio.structure.jama.Matrix; 038 039import javax.swing.*; 040 041import java.awt.*; 042import java.awt.event.*; 043import java.io.StringWriter; 044import java.util.ArrayList; 045import java.util.Arrays; 046import java.util.List; 047 048/** A class that provides a simple GUI for Jmol 049 * 050 * @author Andreas Prlic 051 * @since 1.6 052 * 053 */ 054public class StructureAlignmentJmol extends AbstractAlignmentJmol { 055 056 private Atom[] ca1; 057 private Atom[] ca2; 058 private AFPChain afpChain; 059 060 private static final String LIGAND_DISPLAY_SCRIPT = 061 ResourceManager.getResourceManager("ce"). 062 getString("default.ligand.jmol.script"); 063 064 public static void main(String[] args){ 065 066 try { 067 068 UserConfiguration config = new UserConfiguration(); 069 AtomCache cache = new AtomCache(config); 070 071 Structure struc = cache.getStructure("5pti"); 072 073 StructureAlignmentJmol jmolPanel = 074 new StructureAlignmentJmol(null,null,null); 075 076 jmolPanel.setStructure(struc); 077 078 // send some RASMOL style commands to Jmol 079 jmolPanel.evalString("select * ; color chain;"); 080 jmolPanel.evalString("select *; spacefill off; wireframe off; backbone 0.4; "); 081 082 } catch (Exception e){ 083 e.printStackTrace(); 084 } 085 } 086 087 public StructureAlignmentJmol(){ 088 // don;t have an afpChain, set it to null... 089 this(null, null, null); 090 } 091 092 public StructureAlignmentJmol(AFPChain afpChain, Atom[] ca1, Atom[] ca2) { 093 094 AligUIManager.setLookAndFeel(); 095 096 nrOpenWindows++; 097 jmolPanel = new JmolPanel(); 098 099 frame = new JFrame(); 100 101 JMenuBar menu = MenuCreator.initJmolMenu(frame,this, afpChain, null); 102 103 frame.setJMenuBar(menu); 104 //frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 105 this.afpChain = afpChain; 106 this.ca1 = ca1; 107 this.ca2 = ca2; 108 109 frame.addWindowListener( new WindowAdapter() 110 { 111 112 @Override 113 public void windowClosing(WindowEvent e) { 114 115 nrOpenWindows--; 116 117 destroy(); 118 119 if ( nrOpenWindows > 0) { 120 121 frame.dispose(); 122 } 123 else { 124 // check if AlignmentGUI is visible.. 125 126 AlignmentGui gui = AlignmentGui.getInstanceNoVisibilityChange(); 127 if ( gui.isVisible()) { 128 frame.dispose(); 129 gui.requestFocus(); 130 } else { 131 System.exit(0); 132 } 133 } 134 } 135 }); 136 137 Container contentPane = frame.getContentPane(); 138 139 Box vBox = Box.createVerticalBox(); 140 141 //try { 142 143 144 145 jmolPanel.addMouseMotionListener(this); 146 jmolPanel.addMouseListener(this); 147 148 // } catch (ClassNotFoundException e){ 149 // e.printStackTrace(); 150 // System.err.println("Could not find Jmol in classpath, please install first. http://www.jmol.org"); 151 // return; 152 // } 153 jmolPanel.setPreferredSize(new Dimension(DEFAULT_WIDTH,DEFAULT_HEIGHT)); 154 vBox.add(jmolPanel); 155 156 157 /// USER SCRIPTING COMMAND 158 JTextField field = new JTextField(); 159 160 field.setMaximumSize(new Dimension(Short.MAX_VALUE,30)); 161 field.setText(COMMAND_LINE_HELP); 162 RasmolCommandListener listener = new RasmolCommandListener(jmolPanel,field) ; 163 164 field.addActionListener(listener); 165 field.addMouseListener(listener); 166 field.addKeyListener(listener); 167 vBox.add(field); 168 169 170 /// COMBO BOXES 171 Box hBox1 = Box.createHorizontalBox(); 172 hBox1.add(Box.createGlue()); 173 174 String[] styles = new String[] { "Cartoon", "Backbone", "CPK", "Ball and Stick", "Ligands","Ligands and Pocket"}; 175 JComboBox style = new JComboBox(styles); 176 177 hBox1.setMaximumSize(new Dimension(Short.MAX_VALUE,30)); 178 179 hBox1.add(new JLabel("Style")); 180 hBox1.add(style); 181 vBox.add(hBox1); 182 contentPane.add(vBox); 183 184 style.addActionListener(jmolPanel); 185 186 String[] colorModes = new String[] { "Secondary Structure", "By Chain", "Rainbow", "By Element", "By Amino Acid", "Hydrophobicity" ,"Suggest Domains" , "Show SCOP Domains"}; 187 JComboBox colors = new JComboBox(colorModes); 188 colors.addActionListener(jmolPanel); 189 hBox1.add(Box.createGlue()); 190 hBox1.add(new JLabel("Color")); 191 hBox1.add(colors); 192 193 194 // CHeck boxes 195 Box hBox2 = Box.createHorizontalBox(); 196 hBox2.setMaximumSize(new Dimension(Short.MAX_VALUE,30)); 197 198 JButton resetDisplay = new JButton("Reset Display"); 199 200 resetDisplay.addActionListener(new ActionListener() { 201 202 @Override 203 public void actionPerformed(ActionEvent e) { 204 System.out.println("reset!!"); 205 jmolPanel.executeCmd("restore STATE state_1"); 206 207 } 208 }); 209 210 hBox2.add(resetDisplay); 211 hBox2.add(Box.createGlue()); 212 213 214 JCheckBox toggleSelection = new JCheckBox("Show Selection"); 215 toggleSelection.addItemListener( 216 new ItemListener() { 217 218 @Override 219 public void itemStateChanged(ItemEvent e) { 220 boolean showSelection = (e.getStateChange() == ItemEvent.SELECTED); 221 222 if (showSelection){ 223 jmolPanel.executeCmd("set display selected"); 224 } else { 225 jmolPanel.executeCmd("set display off"); 226 } 227 228 } 229 } 230 ); 231 232 233 234 hBox2.add(toggleSelection); 235 236 hBox2.add(Box.createGlue()); 237 vBox.add(hBox2); 238 239 240 // STATUS DISPLAY 241 242 Box hBox = Box.createHorizontalBox(); 243 244 status = new JTextField(); 245 status.setBackground(Color.white); 246 status.setEditable(false); 247 status.setMaximumSize(new Dimension(Short.MAX_VALUE,30)); 248 status.setPreferredSize(new Dimension(DEFAULT_WIDTH / 2,30)); 249 status.setMinimumSize(new Dimension(DEFAULT_WIDTH / 2,30)); 250 hBox.add(status); 251 text = new JTextField(); 252 text.setBackground(Color.white); 253 text.setMaximumSize(new Dimension(Short.MAX_VALUE,30)); 254 text.setPreferredSize(new Dimension(DEFAULT_WIDTH / 2,30)); 255 text.setMinimumSize(new Dimension(DEFAULT_WIDTH / 2,30)); 256 text.setText("Display of Atom info"); 257 text.setEditable(false); 258 hBox.add(text); 259 260 vBox.add(hBox); 261 262 263 264 contentPane.add(vBox); 265 MyJmolStatusListener li = (MyJmolStatusListener) jmolPanel.getStatusListener(); 266 li.setTextField(status); 267 frame.pack(); 268 frame.setVisible(true); 269 270 271 // init coordinates 272 273 initCoords(); 274 275 resetDisplay(); 276 277 } 278 @Override 279 protected void initCoords(){ 280 try { 281 if ( ca1 == null || ca2 == null ){ 282 if ( structure != null) 283 setStructure(structure); 284 else { 285 //System.err.println("could not find anything to display!"); 286 return; 287 } 288 } 289 Structure artificial = DisplayAFP.getAlignedStructure(ca1,ca2); 290 PDBHeader header = new PDBHeader(); 291 String title = afpChain.getAlgorithmName() + " V." +afpChain.getVersion() + " : " + afpChain.getName1() + " vs. " + afpChain.getName2(); 292 header.setTitle(title); 293 artificial.setPDBHeader(header); 294 setStructure(artificial); 295 } catch (StructureException e){ 296 e.printStackTrace(); 297 } 298 } 299 300 @Override 301 public void destroy(){ 302 super.destroy(); 303 afpChain =null; 304 ca1 = null; 305 ca2 = null; 306 } 307 308 @Override 309 public void actionPerformed(ActionEvent e) { 310 String cmd = e.getActionCommand(); 311 if ( cmd.equals(MenuCreator.TEXT_ONLY)) { 312 if ( afpChain == null) { 313 System.err.println("Currently not viewing an alignment!"); 314 return; 315 } 316 //Clone the AFPChain to not override the FatCat numbers in alnsymb 317 AFPChain textAFP = (AFPChain) afpChain.clone(); 318 String result = AfpChainWriter.toWebSiteDisplay(textAFP, ca1, ca2) ; 319 320 DisplayAFP.showAlignmentImage(afpChain, result); 321 322 } else if ( cmd.equals(MenuCreator.PAIRS_ONLY)) { 323 if ( afpChain == null) { 324 System.err.println("Currently not viewing an alignment!"); 325 return; 326 } 327 String result = AfpChainWriter.toAlignedPairs(afpChain, ca1, ca2) ; 328 329 DisplayAFP.showAlignmentImage(afpChain, result); 330 331 } else if (cmd.equals(MenuCreator.ALIGNMENT_PANEL)){ 332 if ( afpChain == null) { 333 System.err.println("Currently not viewing an alignment!"); 334 return; 335 } 336 try { 337 DisplayAFP.showAlignmentPanel(afpChain, ca1, ca2, this); 338 } catch (Exception e1) { 339 e1.printStackTrace(); 340 return; 341 } 342 343 } else if (cmd.equals(MenuCreator.FATCAT_TEXT)){ 344 if ( afpChain == null) { 345 System.err.println("Currently not viewing an alignment!"); 346 return; 347 } 348 String result = afpChain.toFatcat(ca1, ca2) ; 349 result += AFPChain.newline; 350 result += afpChain.toRotMat(); 351 DisplayAFP.showAlignmentImage(afpChain, result); 352 } 353 } 354 355 public static String getJmolString(AFPChain afpChain, Atom[] ca1, Atom[] ca2){ 356 357 if ( afpChain.getBlockNum() > 1){ 358 return getMultiBlockJmolScript( afpChain, ca1, ca2); 359 } 360 361 362 363 StringBuffer j = new StringBuffer(); 364 j.append(DEFAULT_SCRIPT); 365 366 367 // now color the equivalent residues ... 368 StringBuffer sel = new StringBuffer(); 369 List<String> pdb1 = DisplayAFP.getPDBresnum(0,afpChain,ca1); 370 sel.append("select "); 371 int pos = 0; 372 for (String res :pdb1 ){ 373 if ( pos > 0) 374 sel.append(","); 375 pos++; 376 377 sel.append(res); 378 sel.append("/1"); 379 } 380 if ( pos == 0) 381 sel.append("none"); 382 sel.append(";"); 383 sel.append("backbone 0.6 ; color orange;"); 384 sel.append("select */2; color lightgrey; model 2; "); 385 //jmol.evalString("select */2; color lightgrey; model 2; "); 386 List<String> pdb2 = DisplayAFP.getPDBresnum(1,afpChain,ca2); 387 sel.append("select "); 388 pos = 0; 389 for (String res :pdb2 ){ 390 if ( pos > 0) 391 sel.append(","); 392 pos++; 393 394 sel.append(res); 395 sel.append("/2"); 396 } 397 if ( pos == 0) 398 sel.append("none"); 399 sel.append("; backbone 0.6 ; color cyan;"); 400 //System.out.println(sel); 401 j.append(sel); 402 // now show both models again. 403 j.append("model 0; "); 404 j.append(LIGAND_DISPLAY_SCRIPT); 405 //color [object] cpk , set defaultColors Jmol , set defaultColors Rasmol 406 407 // and now select the aligned residues... 408 StringBuffer buf = new StringBuffer("select "); 409 int count = 0; 410 for (String res : pdb1 ){ 411 if ( count > 0) 412 buf.append(","); 413 buf.append(res); 414 buf.append("/1"); 415 count++; 416 } 417 418 for (String res :pdb2 ){ 419 buf.append(","); 420 buf.append(res); 421 buf.append("/2"); 422 } 423 //buf.append("; set display selected;"); 424 425 j.append(buf); 426 427 return j.toString(); 428 } 429 430 public static String getJmolScript4Block(AFPChain afpChain, Atom[] ca1, Atom[] ca2, int blockNr){ 431 int blockNum = afpChain.getBlockNum(); 432 433 if ( blockNr >= blockNum) 434 return DEFAULT_SCRIPT; 435 436 int[] optLen = afpChain.getOptLen(); 437 int[][][] optAln = afpChain.getOptAln(); 438 439 if ( optLen == null) 440 return DEFAULT_SCRIPT; 441 442 StringWriter jmol = new StringWriter(); 443 jmol.append(DEFAULT_SCRIPT); 444 445 jmol.append("select */2; color lightgrey; model 2; "); 446 447 printJmolScript4Block(ca1, ca2, blockNum, optLen, optAln, jmol, blockNr); 448 449 jmol.append("model 0; "); 450 jmol.append(LIGAND_DISPLAY_SCRIPT); 451 //System.out.println(jmol); 452 return jmol.toString(); 453 454 455 } 456 457 458 private static String getMultiBlockJmolScript(AFPChain afpChain, Atom[] ca1, Atom[] ca2) { 459 460 int blockNum = afpChain.getBlockNum(); 461 int[] optLen = afpChain.getOptLen(); 462 int[][][] optAln = afpChain.getOptAln(); 463 464 if ( optLen == null) 465 return DEFAULT_SCRIPT; 466 467 StringWriter jmol = new StringWriter(); 468 jmol.append(DEFAULT_SCRIPT); 469 470 jmol.append("select */2; color lightgrey; model 2; "); 471 472 for(int bk = 0; bk < blockNum; bk ++) { 473 474 printJmolScript4Block(ca1, ca2, blockNum, optLen, optAln, jmol, bk); 475 } 476 jmol.append("model 0; "); 477 478 jmol.append(LIGAND_DISPLAY_SCRIPT); 479 //System.out.println(jmol); 480 return jmol.toString(); 481 482 483 } 484 485 private static void printJmolScript4Block(Atom[] ca1, Atom[] ca2, int blockNum, 486 int[] optLen, int[][][] optAln, StringWriter jmol, int bk) { 487 //the block nr determines the color... 488 int colorPos = bk; 489 490 Color c1; 491 Color c2; 492 //If the colors for the block are specified in AFPChain use them, otherwise the default ones are calculated 493 494 if ( colorPos > ColorUtils.colorWheel.length){ 495 colorPos = ColorUtils.colorWheel.length % colorPos ; 496 } 497 498 Color end1 = ColorUtils.rotateHue(ColorUtils.orange, (1.0f / 24.0f) * blockNum ); 499 Color end2 = ColorUtils.rotateHue(ColorUtils.cyan, (1.0f / 24.0f) * (blockNum +1) ) ; 500 501 c1 = ColorUtils.getIntermediate(ColorUtils.orange, end1, blockNum, bk); 502 c2 = ColorUtils.getIntermediate(ColorUtils.cyan, end2, blockNum, bk); 503 504 List<String> pdb1 = new ArrayList<String>(); 505 List<String> pdb2 = new ArrayList<String>(); 506 for ( int i=0;i< optLen[bk];i++) { 507 /// 508 int pos1 = optAln[bk][0][i]; 509 pdb1.add(JmolTools.getPdbInfo(ca1[pos1])); 510 int pos2 = optAln[bk][1][i]; 511 pdb2.add(JmolTools.getPdbInfo(ca2[pos2])); 512 } 513 514 // and now select the aligned residues... 515 StringBuffer buf = new StringBuffer("select "); 516 int count = 0; 517 for (String res : pdb1 ){ 518 if ( count > 0) 519 buf.append(","); 520 buf.append(res); 521 buf.append("/1"); 522 count++; 523 } 524 525 buf.append("; backbone 0.6 ; color [" + c1.getRed() +"," + c1.getGreen() +"," +c1.getBlue()+"]; select "); 526 527 count = 0; 528 for (String res :pdb2 ){ 529 if ( count > 0) 530 buf.append(","); 531 532 buf.append(res); 533 buf.append("/2"); 534 count++; 535 } 536 //buf.append("; set display selected;"); 537 538 buf.append("; backbone 0.6 ; color [" + c2.getRed() +"," + c2.getGreen() +"," +c2.getBlue()+"];"); 539 540 // now color this block: 541 jmol.append(buf); 542 } 543 544 @Override 545 public void resetDisplay(){ 546 547 if (afpChain != null && ca1 != null && ca2 != null) { 548 String script = getJmolString( afpChain,ca1,ca2); 549 //System.out.println(script); 550 evalString(script); 551 jmolPanel.evalString("save STATE state_1"); 552 } 553 } 554 555 @Override 556 public List<Matrix> getDistanceMatrices() { 557 if (afpChain == null) return null; 558 else return Arrays.asList(afpChain.getDisTable1(), afpChain.getDisTable2()); 559 } 560}