1 /* $Author: hansonr $ 2 * $Date: 2010-04-22 13:16:44 -0500 (Thu, 22 Apr 2010) $ 3 * $Revision: 12904 $ 4 * 5 * Copyright (C) 2002-2005 The Jmol Development Team 6 * 7 * Contact: jmol-developers@lists.sf.net 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 */ 23 24 package org.jmol.viewer; 25 26 import java.util.Arrays; 27 import java.util.Date; 28 import java.util.Hashtable; 29 import java.util.Map; 30 31 import org.jmol.api.JmolDataManager; 32 import org.jmol.api.JmolModulationSet; 33 import org.jmol.api.JmolScriptFunction; 34 import org.jmol.api.SymmetryInterface; 35 import org.jmol.c.PAL; 36 import org.jmol.c.STR; 37 import org.jmol.c.VDW; 38 import org.jmol.modelset.Atom; 39 import org.jmol.modelset.AtomCollection; 40 import org.jmol.modelset.Bond; 41 import org.jmol.modelset.BondSet; 42 import org.jmol.modelset.Measurement; 43 import org.jmol.modelset.Model; 44 import org.jmol.modelset.ModelSet; 45 import org.jmol.modelset.StateScript; 46 import org.jmol.modelset.Text; 47 import org.jmol.modelset.TickInfo; 48 import org.jmol.script.SV; 49 import org.jmol.script.T; 50 import org.jmol.shape.AtomShape; 51 import org.jmol.shape.Axes; 52 import org.jmol.shape.Balls; 53 import org.jmol.shape.Echo; 54 import org.jmol.shape.FontLineShape; 55 import org.jmol.shape.Frank; 56 import org.jmol.shape.Halos; 57 import org.jmol.shape.Hover; 58 import org.jmol.shape.Labels; 59 import org.jmol.shape.Measures; 60 import org.jmol.shape.Shape; 61 import org.jmol.shape.Sticks; 62 import org.jmol.util.BSUtil; 63 import org.jmol.util.C; 64 import org.jmol.util.ColorEncoder; 65 import org.jmol.util.Edge; 66 import org.jmol.util.Escape; 67 import org.jmol.util.Font; 68 import org.jmol.util.GData; 69 import org.jmol.util.Logger; 70 import org.jmol.util.Vibration; 71 72 import javajs.util.BS; 73 import javajs.util.Lst; 74 import javajs.util.P3; 75 import javajs.util.PT; 76 import javajs.util.SB; 77 78 /** 79 * StateCreator handles all aspects of working with the "state" as 80 * generally defined, including 81 * 82 * -- creating the state script 83 * 84 * -- general output, including logging 85 * 86 * -- handling undo/redo 87 * 88 * -- processing SYNC directives 89 * 90 * 91 * Called by reflection only; all state generation script here, for 92 * modularization in JavaScript 93 * 94 * 95 * 96 */ 97 public class StateCreator extends JmolStateCreator { 98 StateCreator()99 public StateCreator() { 100 101 // by reflection only! 102 103 } 104 105 private Viewer vwr; 106 107 @Override setViewer(Viewer vwr)108 void setViewer(Viewer vwr) { 109 this.vwr = vwr; 110 } 111 112 113 /////////////////// creating the state script //////////////////// 114 115 @Override getStateScript(String type, int width, int height)116 String getStateScript(String type, int width, int height) { 117 //System.out.println("vwr getStateInfo " + type); 118 boolean isAll = (type == null || type.equalsIgnoreCase("all")); 119 SB s = new SB(); 120 SB sfunc = (isAll ? new SB().append("function _setState() {\n") : null); 121 if (isAll) { 122 s.append(JC.STATE_VERSION_STAMP + Viewer.getJmolVersion() + ";\n"); 123 if (vwr.isApplet) { 124 app(s, "# fullName = " + PT.esc(vwr.fullName)); 125 app(s, "# documentBase = " + PT.esc(Viewer.appletDocumentBase)); 126 app(s, "# codeBase = " + PT.esc(Viewer.appletCodeBase)); 127 s.append("\n"); 128 } 129 } 130 131 GlobalSettings global = vwr.g; 132 // window state 133 if (isAll || type.equalsIgnoreCase("windowState")) 134 s.append(getWindowState(sfunc, width, height)); 135 //if (isAll) 136 //s.append(getFunctionCalls(null)); // removed in 12.1.16; unnecessary in state 137 // file state 138 if (isAll || type.equalsIgnoreCase("fileState")) 139 s.append(getFileState(sfunc)); 140 // all state scripts (definitions, dataFrames, calculations, configurations, 141 // rebonding 142 if (isAll || type.equalsIgnoreCase("definedState")) 143 s.append(getDefinedState(sfunc, true)); 144 // numerical values 145 if (isAll || type.equalsIgnoreCase("variableState")) 146 s.append(getParameterState(global, sfunc)); // removed in 12.1.16; unnecessary in state // ARGH!!! 147 if (isAll || type.equalsIgnoreCase("dataState")) 148 s.append(getDataState(sfunc)); 149 // connections, atoms, bonds, labels, echos, shapes 150 if (isAll || type.equalsIgnoreCase("modelState")) 151 s.append(getModelState(sfunc, true, 152 vwr.getBooleanProperty("saveProteinStructureState"))); 153 // color scheme 154 if (isAll || type.equalsIgnoreCase("colorState")) 155 s.append(getColorState(vwr.cm, sfunc)); 156 // frame information 157 if (isAll || type.equalsIgnoreCase("frameState")) 158 s.append(getAnimState(vwr.am, sfunc)); 159 // orientation and slabbing 160 if (isAll || type.equalsIgnoreCase("perspectiveState")) 161 s.append(getViewState(vwr.tm, sfunc)); 162 // display and selections 163 if (isAll || type.equalsIgnoreCase("selectionState")) 164 s.append(getSelectionState(vwr.slm, sfunc)); 165 if (sfunc != null) { 166 app(sfunc, "set refreshing true"); 167 app(sfunc, "set antialiasDisplay " + global.antialiasDisplay); 168 app(sfunc, "set antialiasTranslucent " + global.antialiasTranslucent); 169 app(sfunc, "set antialiasImages " + global.antialiasImages); 170 if (vwr.tm.spinOn) 171 app(sfunc, "spin on"); 172 sfunc.append("}\n\n_setState;\n"); 173 } 174 if (isAll) 175 s.appendSB(sfunc); 176 return s.toString(); 177 } 178 getDataState(SB sfunc)179 private String getDataState(SB sfunc) { 180 SB commands = new SB(); 181 boolean haveData = false; 182 String atomProps = getAtomicPropertyState(-1, null); 183 if (atomProps.length() > 0) { 184 haveData = true; 185 commands.append(atomProps); 186 } 187 if (vwr.userVdws != null) { 188 String info = vwr.getDefaultVdwNameOrData(0, VDW.USER, 189 vwr.bsUserVdws); 190 if (info.length() > 0) { 191 haveData = true; 192 commands.append(info); 193 } 194 } 195 if (vwr.nmrCalculation != null) 196 haveData |= vwr.nmrCalculation.getState(commands); 197 if (vwr.dm != null) 198 haveData |= vwr.dm.getDataState(this, commands); 199 if (!haveData) 200 return ""; 201 202 String cmd = ""; 203 if (sfunc != null) { 204 sfunc.append(" _setDataState;\n"); 205 cmd = "function _setDataState() {\n"; 206 commands.append("}\n\n"); 207 } 208 return cmd + commands.toString(); 209 } 210 getDefinedState(SB sfunc, boolean isAll)211 private String getDefinedState(SB sfunc, boolean isAll) { 212 ModelSet ms = vwr.ms; 213 int len = ms.stateScripts.size(); 214 if (len == 0) 215 return ""; 216 217 boolean haveDefs = false; 218 SB commands = new SB(); 219 String cmd; 220 for (int i = 0; i < len; i++) { 221 StateScript ss = ms.stateScripts.get(i); 222 if (ss.inDefinedStateBlock && (cmd = ss.toString()).length() > 0) { 223 app(commands, cmd); 224 haveDefs = true; 225 } 226 } 227 if (!haveDefs) 228 return ""; 229 cmd = ""; 230 if (isAll && sfunc != null) { 231 sfunc.append(" _setDefinedState;\n"); 232 cmd = "function _setDefinedState() {\n\n"; 233 } 234 if (sfunc != null) 235 commands.append("\n}\n\n"); 236 return cmd + commands.toString(); 237 } 238 239 @Override getModelState(SB sfunc, boolean isAll, boolean withProteinStructure)240 String getModelState(SB sfunc, boolean isAll, boolean withProteinStructure) { 241 SB commands = new SB(); 242 if (isAll && sfunc != null) { 243 sfunc.append(" _setModelState;\n"); 244 commands.append("function _setModelState() {\n"); 245 } 246 String cmd; 247 248 // connections 249 250 ModelSet ms = vwr.ms; 251 Bond[] bonds = ms.bo; 252 Model[] models = ms.am; 253 int modelCount = ms.mc; 254 255 if (isAll) { 256 257 int len = ms.stateScripts.size(); 258 for (int i = 0; i < len; i++) { 259 StateScript ss = ms.stateScripts.get(i); 260 if (!ss.inDefinedStateBlock && (cmd = ss.toString()).length() > 0) { 261 app(commands, cmd); 262 } 263 } 264 265 SB sb = new SB(); 266 for (int i = 0; i < ms.bondCount; i++) 267 if (!models[bonds[i].atom1.mi].isModelKit) 268 if (bonds[i].isHydrogen() || (bonds[i].order & Edge.BOND_NEW) != 0) { 269 Bond bond = bonds[i]; 270 int index = bond.atom1.i; 271 if (bond.atom1.group.isAdded(index)) 272 index = -1 - index; 273 sb.appendI(index).appendC('\t').appendI(bond.atom2.i).appendC('\t') 274 .appendI(bond.order & ~Edge.BOND_NEW).appendC('\t') 275 .appendF(bond.mad / 1000f).appendC('\t') 276 .appendF(bond.getEnergy()).appendC('\t') 277 .append(Edge.getBondOrderNameFromOrder(bond.order)) 278 .append(";\n"); 279 } 280 if (sb.length() > 0) 281 commands.append("data \"connect_atoms\"\n").appendSB(sb) 282 .append("end \"connect_atoms\";\n"); 283 commands.append("\n"); 284 } 285 286 // bond visibility 287 288 if (ms.haveHiddenBonds) { 289 BondSet bs = new BondSet(); 290 for (int i = ms.bondCount; --i >= 0;) 291 if (bonds[i].mad != 0 292 && (bonds[i].shapeVisibilityFlags & Bond.myVisibilityFlag) == 0) 293 bs.set(i); 294 if (bs.isEmpty()) 295 ms.haveHiddenBonds = false; 296 else 297 commands.append(" hide ").append(Escape.eBond(bs)).append(";\n"); 298 } 299 300 // shape construction 301 302 vwr.setModelVisibility(); 303 304 // unnecessary. Removed in 11.5.35 -- oops! 305 306 if (withProteinStructure) 307 commands.append(ms 308 .getProteinStructureState(null, isAll ? T.all : T.state)); 309 310 // introduced in 14.4.2 311 for (int i = 0; i < modelCount; i++) 312 if (models[i].mat4 != null) 313 commands.append(" frame orientation " + ms.getModelNumberDotted(i) 314 + Escape.matrixToScript(models[i].mat4) + ";\n"); 315 316 getShapeStatePriv(commands, isAll, Integer.MAX_VALUE); 317 318 if (isAll) { 319 boolean needOrientations = false; 320 for (int i = 0; i < modelCount; i++) 321 if (models[i].isJmolDataFrame) { 322 needOrientations = true; 323 break; 324 } 325 SB sb = new SB(); 326 for (int i = 0; i < modelCount; i++) { 327 Model m = models[i]; 328 sb.setLength(0); 329 String s = (String) ms.getInfo(i, "modelID"); 330 if (s != null && !s.equals(ms.getInfo(i, "modelID0"))) 331 sb.append(" frame ID ").append(PT.esc(s)).append(";\n"); 332 String t = ms.frameTitles[i]; 333 if (t != null && t.length() > 0) 334 sb.append(" frame title ").append(PT.esc(t)).append(";\n"); 335 if (needOrientations && m.orientation != null 336 && !ms.isTrajectorySubFrame(i)) 337 sb.append(" ").append(m.orientation.getMoveToText(false)) 338 .append(";\n"); 339 if (m.frameDelay != 0 && !ms.isTrajectorySubFrame(i)) 340 sb.append(" frame delay ").appendF(m.frameDelay / 1000f) 341 .append(";\n"); 342 if (m.simpleCage != null) { 343 sb.append(" unitcell ") 344 .append(Escape.eAP(m.simpleCage.getUnitCellVectors())) 345 .append(";\n"); 346 getShapeStatePriv(sb, isAll, JC.SHAPE_UCCAGE); 347 } 348 if (sb.length() > 0) 349 commands.append(" frame " + ms.getModelNumberDotted(i) + ";\n") 350 .appendSB(sb); 351 } 352 353 boolean loadUC = false; 354 if (ms.unitCells != null) { 355 boolean haveModulation = false; 356 for (int i = 0; i < modelCount; i++) { 357 SymmetryInterface symmetry = ms.getUnitCell(i); 358 if (symmetry == null) 359 continue; 360 sb.setLength(0); 361 if (symmetry.getState(sb)) { 362 loadUC = true; 363 commands.append(" frame ").append(ms.getModelNumberDotted(i)) 364 .appendSB(sb).append(";\n"); 365 } 366 haveModulation |= (vwr.ms.getLastVibrationVector(i, T.modulation) >= 0); 367 } 368 if (loadUC) 369 vwr.shm.loadShape(JC.SHAPE_UCCAGE); // just in case 370 getShapeStatePriv(commands, isAll, JC.SHAPE_UCCAGE); 371 if (haveModulation) { 372 Map<String, BS> temp = new Hashtable<String, BS>(); 373 int ivib; 374 for (int i = modelCount; --i >= 0;) { 375 if ((ivib = vwr.ms.getLastVibrationVector(i, T.modulation)) >= 0) 376 for (int j = models[i].firstAtomIndex; j <= ivib; j++) { 377 JmolModulationSet mset = ms.getModulation(j); 378 if (mset != null) 379 BSUtil.setMapBitSet(temp, j, j, mset.getState()); 380 } 381 } 382 commands.append(getCommands(temp, null, "select")); 383 } 384 } 385 commands.append(" set fontScaling " + vwr.getBoolean(T.fontscaling) 386 + ";\n"); 387 // if (vwr.getBoolean(T.modelkitmode)) 388 // commands.append(" set modelKitMode true;\n"); 389 } 390 if (sfunc != null) 391 commands.append("\n}\n\n"); 392 return commands.toString(); 393 } 394 getWindowState(SB sfunc, int width, int height)395 private String getWindowState(SB sfunc, int width, int height) { 396 GlobalSettings global = vwr.g; 397 SB str = new SB(); 398 if (sfunc != null) { 399 sfunc 400 .append(" initialize;\n set refreshing false;\n _setWindowState;\n"); 401 str.append("\nfunction _setWindowState() {\n"); 402 } 403 if (width != 0) 404 str.append("# preferredWidthHeight ").appendI(width).append(" ").appendI( 405 height).append(";\n"); 406 str.append("# width ") 407 .appendI(width == 0 ? vwr.getScreenWidth() : width).append( 408 ";\n# height ").appendI( 409 height == 0 ? vwr.getScreenHeight() : height).append(";\n"); 410 app(str, "stateVersion = " + JC.versionInt); 411 app(str, "background " + Escape.escapeColor(global.objColors[0])); 412 for (int i = 1; i < StateManager.OBJ_MAX; i++) 413 if (global.objColors[i] != 0) 414 app(str, StateManager.getObjectNameFromId(i) + "Color = \"" 415 + Escape.escapeColor(global.objColors[i]) + '"'); 416 if (global.backgroundImageFileName != null) { 417 app(str, "background IMAGE " 418 + (global.backgroundImageFileName.startsWith(";base64,") ? "" : "/*file*/") 419 + PT.esc(global.backgroundImageFileName)); 420 } 421 str.append(getLightingState(false)); 422 //app(str, "statusReporting = " + global.statusReporting); 423 if (sfunc != null) 424 str.append("}\n\n"); 425 return str.toString(); 426 } 427 428 @Override getLightingState(boolean isAll)429 String getLightingState(boolean isAll) { 430 SB str = new SB(); 431 GData g = vwr.gdata; 432 app(str, "set ambientPercent " + g.getAmbientPercent()); 433 app(str, "set diffusePercent " + g.getDiffusePercent()); 434 app(str, "set specular " + g.getSpecular()); 435 app(str, "set specularPercent " + g.getSpecularPercent()); 436 app(str, "set specularPower " + g.getSpecularPower()); 437 int se = g.getSpecularExponent(); 438 int pe = g.getPhongExponent(); 439 app(str, (Math.pow(2, se) == pe ? "set specularExponent " + se : "set phongExponent " + pe)); 440 app(str, "set celShading " + g.getCel()); 441 app(str, "set celShadingPower " + g.getCelPower()); 442 app(str, "set zShadePower " + vwr.g.zShadePower); 443 if (isAll) 444 getZshadeState(str, vwr.tm, true); 445 return str.toString(); 446 } 447 getFileState(SB sfunc)448 private String getFileState(SB sfunc) { 449 SB commands = new SB(); 450 if (sfunc != null) { 451 sfunc.append(" _setFileState;\n"); 452 commands.append("function _setFileState() {\n\n"); 453 } 454 if (commands.indexOf("append") < 0 455 && vwr.getModelSetFileName().equals(JC.ZAP_TITLE)) 456 commands.append(" zap;\n"); 457 appendLoadStates(commands); 458 if (sfunc != null) 459 commands.append("\n}\n\n"); 460 return commands.toString(); 461 } 462 appendLoadStates(SB cmds)463 private void appendLoadStates(SB cmds) { 464 Map<String, Boolean> ligandModelSet = vwr.ligandModelSet; 465 if (ligandModelSet != null) { 466 for (String key : ligandModelSet.keySet()) { 467 String data = (String) vwr.ligandModels.get(key + "_data"); 468 if (data != null) 469 cmds.append(" ").append( 470 Escape.encapsulateData("ligand_" + key, data.trim() + "\n", JmolDataManager.DATA_TYPE_STRING)); 471 data = (String) vwr.ligandModels.get(key + "_file"); 472 if (data != null) 473 cmds.append(" ").append( 474 Escape.encapsulateData("file_" + key, data.trim() + "\n", JmolDataManager.DATA_TYPE_STRING)); 475 } 476 } 477 SB commands = new SB(); 478 ModelSet ms = vwr.ms; 479 Model[] models = ms.am; 480 int modelCount = ms.mc; 481 for (int i = 0; i < modelCount; i++) { 482 if (ms.isJmolDataFrameForModel(i) || ms.isTrajectorySubFrame(i)) 483 continue; 484 Model m = models[i]; 485 int pt = commands.indexOf(m.loadState); 486 if (pt < 0 || pt != commands.lastIndexOf(m.loadState)) 487 commands.append(models[i].loadState); 488 if (models[i].isModelKit) { 489 BS bs = ms.getModelAtomBitSetIncludingDeleted(i, false); 490 if (ms.tainted != null) { 491 if (ms.tainted[AtomCollection.TAINT_COORD] != null) 492 ms.tainted[AtomCollection.TAINT_COORD].andNot(bs); 493 if (ms.tainted[AtomCollection.TAINT_ELEMENT] != null) 494 ms.tainted[AtomCollection.TAINT_ELEMENT].andNot(bs); 495 } 496 m.loadScript = new SB(); 497 getInlineData(commands, vwr.getModelExtract(bs, false, true, "MOL"), 498 i > 0, null, null); 499 } else { 500 commands.appendSB(m.loadScript); 501 Lst<String> auxFiles = (Lst<String>) m.auxiliaryInfo.get("auxFiles"); 502 if (auxFiles != null) { 503 for (int j = 0; j < auxFiles.size(); j++) 504 commands.append(";#FILE1=" + PT.esc(auxFiles.get(j)) + ";"); 505 } 506 } 507 } 508 String s = commands.toString(); 509 // add a zap command before the first load command. 510 if (s.indexOf("data \"append ") < 0) { 511 int i = s.indexOf("load /*data*/"); 512 int j = s.indexOf("load /*file*/"); 513 if (j >= 0 && j < i) 514 i = j; 515 if ((j = s.indexOf("load \"@")) >= 0 && j < i) 516 i = j; 517 if (i >= 0) 518 s = s.substring(0, i) + "zap;" + s.substring(i); 519 } 520 cmds.append(s); 521 } 522 523 @Override getInlineData(SB loadScript, String strModel, boolean isAppend, Integer appendToModelIndex, String loadFilter)524 public void getInlineData(SB loadScript, String strModel, boolean isAppend, Integer appendToModelIndex, String loadFilter) { 525 String tag = (isAppend ? "append" 526 + (appendToModelIndex != null && appendToModelIndex.intValue() != vwr.ms.mc - 1 ? " modelindex=" + appendToModelIndex : "") 527 : "model") + " inline"; 528 loadScript.append("load /*data*/ data \"") 529 .append(tag).append("\"\n") 530 .append(strModel).append("end \"").append(tag) 531 .append(loadFilter == null || loadFilter.length() == 0 ? "" : " filter" + PT.esc(loadFilter)) 532 .append("\";"); 533 } 534 getColorState(ColorManager cm, SB sfunc)535 private String getColorState(ColorManager cm, SB sfunc) { 536 SB s = new SB(); 537 int n = getCEState(cm.ce, s); 538 //String colors = getColorSchemeList(getColorSchemeArray(USER)); 539 //if (colors.length() > 0) 540 //s.append("userColorScheme = " + colors + ";\n"); 541 if (n > 0 && sfunc != null) 542 sfunc.append("\n _setColorState\n"); 543 return (n > 0 && sfunc != null ? "function _setColorState() {\n" 544 + s.append("}\n\n").toString() : s.toString()); 545 } 546 getCEState(ColorEncoder p, SB s)547 private int getCEState(ColorEncoder p, SB s) { 548 int n = 0; 549 for (Map.Entry<String, int[]> entry : p.schemes.entrySet()) { 550 String name = entry.getKey(); 551 if (name.length() > 0 & n++ >= 0) 552 s.append("color \"" + name + "=" 553 + ColorEncoder.getColorSchemeList(entry.getValue()) + "\";\n"); 554 } 555 return n; 556 } 557 getAnimState(AnimationManager am, SB sfunc)558 private String getAnimState(AnimationManager am, SB sfunc) { 559 int modelCount = vwr.ms.mc; 560 if (modelCount < 2) 561 return ""; 562 SB commands = new SB(); 563 if (sfunc != null) { 564 sfunc.append(" _setFrameState;\n"); 565 commands.append("function _setFrameState() {\n"); 566 } 567 commands.append("# frame state;\n"); 568 commands.append("# modelCount ").appendI(modelCount).append(";\n# first ") 569 .append(vwr.getModelNumberDotted(0)).append(";\n# last ") 570 .append(vwr.getModelNumberDotted(modelCount - 1)).append(";\n"); 571 if (am.backgroundModelIndex >= 0) 572 app(commands, 573 "set backgroundModel " 574 + vwr.getModelNumberDotted(am.backgroundModelIndex)); 575 if (vwr.tm.bsFrameOffsets != null) { 576 app(commands, "frame align " + Escape.eBS(vwr.tm.bsFrameOffsets)); 577 } else if (vwr.ms.translations != null) { 578 for (int i = modelCount; --i >= 0;) { 579 P3 t = (vwr.ms.getTranslation(i)); 580 if (t != null) 581 app(commands, "frame " + vwr.ms.getModelNumberDotted(i) + " align " 582 + t); 583 } 584 } 585 app(commands, 586 "frame RANGE " + am.getModelSpecial(AnimationManager.FRAME_FIRST) + " " 587 + am.getModelSpecial(AnimationManager.FRAME_LAST)); 588 app(commands, "animation DIRECTION " 589 + (am.animationDirection == 1 ? "+1" : "-1")); 590 app(commands, "animation FPS " + am.animationFps); 591 app(commands, "animation MODE " + T.nameOf(am.animationReplayMode) + " " 592 + am.firstFrameDelay + " " + am.lastFrameDelay); 593 if (am.morphCount > 0) 594 app(commands, "animation MORPH " + am.morphCount); 595 boolean showModel = true; 596 if (am.animationFrames != null) { 597 app(commands, "anim frames " + Escape.eAI(am.animationFrames)); 598 int i = am.caf; 599 app(commands, "frame " + (i + 1)); 600 showModel = (am.cmi != am.modelIndexForFrame(i)); 601 } 602 if (showModel) { 603 String s = am.getModelSpecial(AnimationManager.MODEL_CURRENT); 604 app(commands, s.equals("0") ? "frame *" : "model " + s); 605 } 606 app(commands, "animation " 607 + (!am.animationOn ? "OFF" : am.currentDirection == 1 ? "PLAY" 608 : "PLAYREV")); 609 if (am.animationOn && am.animationPaused) 610 app(commands, "animation PAUSE"); 611 if (sfunc != null) 612 commands.append("}\n\n"); 613 return commands.toString(); 614 } 615 616 /** 617 * note that these are not user variables, only global jmol parameters 618 * 619 * @param global 620 * @param sfunc 621 * @return String 622 */ getParameterState(GlobalSettings global, SB sfunc)623 private String getParameterState(GlobalSettings global, SB sfunc) { 624 String[] list = new String[global.htBooleanParameterFlags.size() 625 + global.htNonbooleanParameterValues.size()]; 626 SB commands = new SB(); 627 boolean isState = (sfunc != null); 628 if (isState) { 629 sfunc.append(" _setParameterState;\n"); 630 commands.append("function _setParameterState() {\n\n"); 631 } 632 int n = 0; 633 //booleans 634 for (String key : global.htBooleanParameterFlags.keySet()) 635 if (GlobalSettings.doReportProperty(key)) 636 list[n++] = "set " + key + " " 637 + global.htBooleanParameterFlags.get(key); 638 for (String key : global.htNonbooleanParameterValues.keySet()) 639 if (GlobalSettings.doReportProperty(key)) { 640 Object value = global.htNonbooleanParameterValues.get(key); 641 if (key.charAt(0) == '=') { 642 //save as =xxxx if you don't want "set" to be there first 643 // (=color [element], =frame ...; set unitcell) -- see Viewer.java 644 key = key.substring(1); 645 } else { 646 // one error here is that defaultLattice is being saved as the 647 // escaped string set defaultLattice "{...}", which actually is not read 648 // and was being improperly read as "{1 1 1}". 649 // leaving it here as it is, now always setting {0 0 0} 650 // otherwise we will break states 651 key = (key.indexOf("default") == 0 ? " " : "") + "set " + key; 652 value = Escape.e(value); 653 } 654 list[n++] = key + " " + value; 655 } 656 switch (global.axesMode) { 657 case T.axesunitcell: 658 list[n++] = "set axes unitcell"; 659 break; 660 case T.axesmolecular: 661 list[n++] = "set axes molecular"; 662 break; 663 default: 664 list[n++] = "set axes window"; 665 } 666 667 Arrays.sort(list, 0, n); 668 for (int i = 0; i < n; i++) 669 if (list[i] != null) 670 app(commands, list[i]); 671 672 String s = StateManager.getVariableList(global.htUserVariables, 0, false, 673 true); 674 if (s.length() > 0) { 675 commands.append("\n#user-defined atom sets; \n"); 676 commands.append(s); 677 } 678 679 // label defaults 680 681 if (vwr.shm.getShape(JC.SHAPE_LABELS) != null) 682 commands 683 .append(getDefaultLabelState((Labels) vwr.shm.shapes[JC.SHAPE_LABELS])); 684 685 // structure defaults 686 687 if (global.haveSetStructureList) { 688 Map<STR, float[]> slist = global.structureList; 689 commands.append("struture HELIX set " 690 + Escape.eAF(slist.get(STR.HELIX))); 691 commands.append("struture SHEET set " 692 + Escape.eAF(slist.get(STR.SHEET))); 693 commands.append("struture TURN set " 694 + Escape.eAF(slist.get(STR.TURN))); 695 } 696 if (sfunc != null) 697 commands.append("\n}\n\n"); 698 return commands.toString(); 699 } 700 getDefaultLabelState(Labels l)701 private String getDefaultLabelState(Labels l) { 702 SB s = new SB().append("\n# label defaults;\n"); 703 app(s, "select none"); 704 app(s, Shape.getColorCommand("label", l.defaultPaletteID, 705 l.defaultColix, l.translucentAllowed)); 706 app(s, "background label " + Shape.encodeColor(l.defaultBgcolix)); 707 app(s, "set labelOffset " + JC.getXOffset(l.defaultOffset) 708 + " " + (JC.getYOffset(l.defaultOffset))); 709 String align = JC.getHorizAlignmentName(l.defaultAlignment); 710 app(s, "set labelAlignment " + (align.length() < 5 ? "left" : align)); 711 String pointer = JC.getPointerName(l.defaultPointer); 712 app(s, "set labelPointer " 713 + (pointer.length() == 0 ? "off" : pointer)); 714 if ((l.defaultZPos & JC.LABEL_ZPOS_FRONT) != 0) 715 app(s, "set labelFront"); 716 else if ((l.defaultZPos & JC.LABEL_ZPOS_GROUP) != 0) 717 app(s, "set labelGroup"); 718 app(s, Shape.getFontCommand("label", Font 719 .getFont3D(l.defaultFontId))); 720 return s.toString(); 721 } 722 getSelectionState(SelectionManager sm, SB sfunc)723 private String getSelectionState(SelectionManager sm, SB sfunc) { 724 SB commands = new SB(); 725 if (sfunc != null) { 726 sfunc.append(" _setSelectionState;\n"); 727 commands.append("function _setSelectionState() {\n"); 728 } 729 if (vwr.ms.trajectory != null) 730 app(commands, vwr.ms.trajectory.getState()); 731 Map<String, BS> temp = new Hashtable<String, BS>(); 732 String cmd = null; 733 addBs(commands, "hide ", sm.bsHidden); 734 addBs(commands, "subset ", sm.bsSubset); 735 addBs(commands, "delete ", sm.bsDeleted); 736 addBs(commands, "fix ", sm.bsFixed); 737 temp.put("-", vwr.slm.getSelectedAtomsNoSubset()); 738 cmd = getCommands(temp, null, "select"); 739 if (cmd == null) 740 app(commands, "select none"); 741 else 742 commands.append(cmd); 743 app(commands, "set hideNotSelected " + sm.hideNotSelected); 744 commands.append((String) vwr.getShapeProperty(JC.SHAPE_STICKS, 745 "selectionState")); 746 if (vwr.getSelectionHalosEnabled()) 747 app(commands, "SelectionHalos ON"); 748 if (sfunc != null) 749 commands.append("}\n\n"); 750 return commands.toString(); 751 } 752 getViewState(TransformManager tm, SB sfunc)753 private String getViewState(TransformManager tm, SB sfunc) { 754 SB commands = new SB(); 755 String moveToText = tm.getMoveToText(0, false); 756 // finalizes transform parameters, in case that has not been done 757 if (sfunc != null) { 758 sfunc.append(" _setPerspectiveState;\n"); 759 commands.append("function _setPerspectiveState() {\n"); 760 } 761 app(commands, "set perspectiveModel " + tm.perspectiveModel); 762 app(commands, "set scaleAngstromsPerInch " 763 + tm.scale3DAngstromsPerInch); 764 app(commands, "set perspectiveDepth " + tm.perspectiveDepth); 765 app(commands, "set visualRange " + tm.visualRangeAngstroms); 766 if (!tm.isWindowCentered()) 767 app(commands, "set windowCentered false"); 768 app(commands, "set cameraDepth " + tm.cameraDepth); 769 boolean navigating = (tm.mode == TransformManager.MODE_NAVIGATION); 770 if (navigating) 771 app(commands, "set navigationMode true"); 772 app(commands, vwr.ms.getBoundBoxCommand(false)); 773 app(commands, "center " + Escape.eP(tm.fixedRotationCenter)); 774 commands.append(vwr.getOrientationText(T.name, null, null).toString()); 775 776 app(commands, moveToText); 777 // stereo mode should not be in the state - just a display option 778 // if (tm.stereoMode != STER.NONE) 779 // app(commands, "stereo " 780 // + (tm.stereoColors == null ? tm.stereoMode.getName() : Escape 781 // .escapeColor(tm.stereoColors[0]) 782 // + " " + Escape.escapeColor(tm.stereoColors[1])) + " " 783 // + tm.stereoDegrees); 784 if (!navigating && !tm.zoomEnabled) 785 app(commands, "zoom off"); 786 commands.append(" slab ").appendI(tm.slabPercentSetting).append(";depth ") 787 .appendI(tm.depthPercentSetting).append( 788 tm.slabEnabled && !navigating ? ";slab on" : "").append(";\n"); 789 commands.append(" set slabRange ").appendF(tm.slabRange).append(";\n"); 790 if (tm.slabPlane != null) 791 commands.append(" slab plane ").append(Escape.eP4(tm.slabPlane)).append( 792 ";\n"); 793 if (tm.depthPlane != null) 794 commands.append(" depth plane ").append(Escape.eP4(tm.depthPlane)) 795 .append(";\n"); 796 getZshadeState(commands, tm, false); 797 commands.append(getSpinState(true)).append("\n"); 798 if (vwr.ms.modelSetHasVibrationVectors() && tm.vibrationOn) 799 app(commands, "set vibrationPeriod " + tm.vibrationPeriod 800 + ";vibration on"); 801 boolean slabInternal = (tm.depthPlane != null || tm.slabPlane != null); 802 if (navigating) { 803 commands.append(tm.getNavigationState()); 804 } 805 if (!tm.slabEnabled && slabInternal) 806 commands.append(" slab off;\n"); 807 if (sfunc != null) 808 commands.append("}\n\n"); 809 return commands.toString(); 810 } 811 getZshadeState(SB s, TransformManager tm, boolean isAll)812 private void getZshadeState(SB s, TransformManager tm, boolean isAll) { 813 814 if (isAll) { 815 app(s,"set zDepth " + tm.zDepthPercentSetting); 816 app(s,"set zSlab " + tm.zSlabPercentSetting); 817 if (!tm.zShadeEnabled) 818 app(s,"set zShade false"); 819 } 820 if (tm.zShadeEnabled) 821 app(s, "set zShade true"); 822 try { 823 if (tm.zSlabPoint != null) 824 app(s,"set zSlab " + Escape.eP(tm.zSlabPoint)); 825 } catch (Exception e) { 826 // don't care 827 } 828 } 829 830 831 /** 832 * @param isAll 833 * @return spin state 834 */ 835 @Override getSpinState(boolean isAll)836 String getSpinState(boolean isAll) { 837 TransformManager tm = vwr.tm; 838 String s = " set spinX " + (int) tm.spinX + "; set spinY " 839 + (int) tm.spinY + "; set spinZ " + (int) tm.spinZ + "; set spinFps " 840 + (int) tm.spinFps + ";"; 841 if (!Float.isNaN(tm.navFps)) 842 s += " set navX " + (int) tm.navX + "; set navY " + (int) tm.navY 843 + "; set navZ " + (int) tm.navZ + "; set navFps " + (int) tm.navFps 844 + ";"; 845 if (tm.navOn) 846 s += " navigation on;"; 847 if (!tm.spinOn) 848 return s; 849 String prefix = (tm.isSpinSelected ? "\n select " 850 + Escape.eBS(vwr.bsA()) + ";\n rotateSelected" 851 : "\n "); 852 if (tm.isSpinInternal) { 853 P3 pt = P3.newP(tm.internalRotationCenter); 854 pt.sub(tm.rotationAxis); 855 s += prefix + " spin " + tm.rotationRate + " " 856 + Escape.eP(tm.internalRotationCenter) + " " + Escape.eP(pt); 857 } else if (tm.isSpinFixed) { 858 s += prefix + " spin axisangle " + Escape.eP(tm.rotationAxis) + " " 859 + tm.rotationRate; 860 } else { 861 s += " spin on"; 862 } 863 return s + ";"; 864 } 865 866 //// info 867 868 //// utility methods 869 870 @Override getCommands(Map<String, BS> htDefine, Map<String, BS> htMore, String selectCmd)871 String getCommands(Map<String, BS> htDefine, Map<String, BS> htMore, 872 String selectCmd) { 873 SB s = new SB(); 874 String setPrev = getCommands2(htDefine, s, null, selectCmd); 875 if (htMore != null) 876 getCommands2(htMore, s, setPrev, "select"); 877 return s.toString(); 878 } 879 getCommands2(Map<String, BS> ht, SB s, String setPrev, String selectCmd)880 private String getCommands2(Map<String, BS> ht, SB s, String setPrev, 881 String selectCmd) { 882 if (ht == null) 883 return ""; 884 for (Map.Entry<String, BS> entry : ht.entrySet()) { 885 String key = entry.getKey(); 886 String set = Escape.eBS(entry.getValue()); 887 if (set.length() < 5) // nothing selected 888 continue; 889 set = selectCmd + " " + set; 890 if (!set.equals(setPrev)) 891 app(s, set); 892 setPrev = set; 893 if (key.indexOf("-") != 0) // - for key means none required 894 app(s, key); 895 } 896 return setPrev; 897 } 898 app(SB s, String cmd)899 private void app(SB s, String cmd) { 900 if (cmd.length() != 0) 901 s.append(" ").append(cmd).append(";\n"); 902 } 903 addBs(SB sb, String key, BS bs)904 private void addBs(SB sb, String key, BS bs) { 905 if (bs == null || bs.length() == 0) 906 return; 907 app(sb, key + Escape.eBS(bs)); 908 } 909 getFontState(String myType, Font font3d)910 private String getFontState(String myType, Font font3d) { 911 int objId = StateManager.getObjectIdFromName(myType 912 .equalsIgnoreCase("axes") ? "axis" : myType); 913 if (objId < 0) 914 return ""; 915 int mad = vwr.getObjectMad10(objId); 916 SB s = new SB().append("\n"); 917 app(s, myType 918 + (mad == 0 ? " off" : mad == 1 ? " on" : mad == -1 ? " dotted" 919 : mad < 20 ? " " + mad : " " + (mad / 20000f))); 920 if (s.length() < 3) 921 return ""; 922 String fcmd = Shape.getFontCommand(myType, font3d); 923 if (fcmd.length() > 0) 924 fcmd = " " + fcmd + ";\n"; 925 return (s + fcmd); 926 } 927 appendTickInfo(String myType, SB sb, TickInfo t)928 private void appendTickInfo(String myType, SB sb, TickInfo t) { 929 sb.append(" "); 930 sb.append(myType); 931 addTickInfo(sb, t, false); 932 sb.append(";\n"); 933 } 934 addTickInfo(SB sb, TickInfo tickInfo, boolean addFirst)935 private static void addTickInfo(SB sb, TickInfo tickInfo, boolean addFirst) { 936 sb.append(" ticks ").append(tickInfo.type).append(" ").append( 937 Escape.eP(tickInfo.ticks)); 938 boolean isUnitCell = (tickInfo.scale != null && Float 939 .isNaN(tickInfo.scale.x)); 940 if (isUnitCell) 941 sb.append(" UNITCELL"); 942 if (tickInfo.tickLabelFormats != null) 943 sb.append(" format ") 944 .append(Escape.eAS(tickInfo.tickLabelFormats, false)); 945 if (!isUnitCell && tickInfo.scale != null) 946 sb.append(" scale ").append(Escape.eP(tickInfo.scale)); 947 if (addFirst && !Float.isNaN(tickInfo.first) && tickInfo.first != 0) 948 sb.append(" first ").appendF(tickInfo.first); 949 if (tickInfo.reference != null) // not implemented 950 sb.append(" point ").append(Escape.eP(tickInfo.reference)); 951 } 952 getMeasurementState(Measures shape)953 private String getMeasurementState(Measures shape) { 954 955 Lst<Measurement> mList = shape.measurements; 956 int measurementCount = shape.measurementCount; 957 Font font3d = Measures.font3d; 958 TickInfo ti = shape.defaultTickInfo; 959 SB commands = new SB(); 960 app(commands, "measures delete"); 961 for (int i = 0; i < measurementCount; i++) { 962 Measurement m = mList.get(i); 963 boolean isProperty = (m.property != null); 964 if (isProperty && Float.isNaN(m.value)) 965 continue; 966 int count = m.count; 967 SB sb = new SB().append("measure"); 968 if (m.thisID != null) 969 sb.append(" ID ").append(PT.esc(m.thisID)); 970 if (m.mad != 0) 971 sb.append(" radius ").appendF( 972 m.thisID == null || m.mad > 0 ? m.mad / 2000f : 0); 973 if (m.colix != 0) 974 sb.append(" color ").append(Escape.escapeColor(C.getArgb(m.colix))); 975 if (m.text != null) { 976 if (m.text.font != null) 977 sb.append(" font ").append(m.text.font.getInfo()); 978 if (m.text.align != JC.TEXT_ALIGN_NONE) 979 sb.append(" align ").append(JC.getHorizAlignmentName(m.text.align)); 980 if (m.text.pymolOffset != null) 981 sb.append(" offset ").append(Escape.eAF(m.text.pymolOffset)); 982 } 983 TickInfo tickInfo = m.tickInfo; 984 if (tickInfo != null) 985 addTickInfo(sb, tickInfo, true); 986 for (int j = 1; j <= count; j++) 987 sb.append(" ").append(m.getLabel(j, true, true)); 988 if (isProperty) 989 sb.append(" " + m.property + " value " + (Float.isNaN(m.value) ? 0f : m.value)) 990 .append(" " + PT.esc(m.getString())); 991 //sb.append("; # " + shape.getInfoAsString(i)); 992 app(commands, sb.toString()); 993 } 994 app(commands, Shape.getFontCommand("measures", font3d)); 995 int nHidden = 0; 996 Map<String, BS> temp = new Hashtable<String, BS>(); 997 BS bs = BS.newN(measurementCount); 998 for (int i = 0; i < measurementCount; i++) { 999 Measurement m = mList.get(i); 1000 if (m.isHidden) { 1001 nHidden++; 1002 bs.set(i); 1003 } 1004 if (shape.bsColixSet != null && shape.bsColixSet.get(i)) 1005 BSUtil.setMapBitSet(temp, i, i, Shape.getColorCommandUnk("measure", 1006 m.colix, shape.translucentAllowed)); 1007 1008 } 1009 if (nHidden > 0) 1010 if (nHidden == measurementCount) 1011 app(commands, "measures off; # lines and numbers off"); 1012 else 1013 for (int i = 0; i < measurementCount; i++) 1014 if (bs.get(i)) 1015 BSUtil.setMapBitSet(temp, i, i, "measure off"); 1016 if (ti != null) { 1017 commands.append(" measure "); 1018 addTickInfo(commands, ti, true); 1019 commands.append(";\n"); 1020 } 1021 if (shape.mad >= 0) 1022 commands.append(" set measurements ").appendF(shape.mad / 2000f).append(";\n"); 1023 String s = getCommands(temp, null, "select measures"); 1024 if (s != null && s.length() != 0) { 1025 commands.append(s); 1026 app(commands, "select measures ({null})"); 1027 } 1028 1029 return commands.toString(); 1030 } 1031 1032 private Map<String, BS> temp = new Hashtable<String, BS>(); 1033 private Map<String, BS> temp2 = new Hashtable<String, BS>(); 1034 private Map<String, BS> temp3 = new Hashtable<String, BS>(); 1035 getShapeStatePriv(SB commands, boolean isAll, int iShape)1036 private void getShapeStatePriv(SB commands, boolean isAll, int iShape) { 1037 Shape[] shapes = vwr.shm.shapes; 1038 if (shapes == null) 1039 return; 1040 int i; 1041 int imax; 1042 if (iShape == Integer.MAX_VALUE) { 1043 i = 0; 1044 imax = JC.SHAPE_MAX; 1045 } else { 1046 imax = (i = iShape) + 1; 1047 } 1048 for (; i < imax; ++i) { 1049 Shape shape = shapes[i]; 1050 if (shape != null 1051 && (isAll || i >= JC.SHAPE_MIN_SECONDARY 1052 && i < JC.SHAPE_MAX_SECONDARY)) { 1053 String cmd = getShapeState(shape); 1054 if (cmd != null && cmd.length() > 1) 1055 commands.append(cmd); 1056 } 1057 } 1058 commands.append(" select *;\n"); 1059 } 1060 getBondState(Sticks shape)1061 private String getBondState(Sticks shape) { 1062 BS bsOrderSet = shape.bsOrderSet; 1063 boolean reportAll = shape.reportAll; 1064 clearTemp(); 1065 ModelSet modelSet = vwr.ms; 1066 boolean haveTainted = false; 1067 Bond[] bonds = modelSet.bo; 1068 int bondCount = modelSet.bondCount; 1069 short r; 1070 1071 if (reportAll || shape.bsSizeSet != null) { 1072 int i0 = (reportAll ? bondCount - 1 : shape.bsSizeSet.nextSetBit(0)); 1073 for (int i = i0; i >= 0; i = (reportAll ? i - 1 : shape.bsSizeSet 1074 .nextSetBit(i + 1))) 1075 BSUtil.setMapBitSet(temp, i, i, "wireframe " 1076 + ((r = bonds[i].mad) == 1 ? "on" : "" + PT.escF(r / 2000f))); 1077 } 1078 if (reportAll || bsOrderSet != null) { 1079 int i0 = (reportAll ? bondCount - 1 : bsOrderSet.nextSetBit(0)); 1080 for (int i = i0; i >= 0; i = (reportAll ? i - 1 : bsOrderSet 1081 .nextSetBit(i + 1))) { 1082 Bond bond = bonds[i]; 1083 if (reportAll || (bond.order & Edge.BOND_NEW) == 0) 1084 BSUtil.setMapBitSet(temp, i, i, "bondOrder " 1085 + Edge.getBondOrderNameFromOrder(bond.order)); 1086 } 1087 } 1088 if (shape.bsColixSet != null) 1089 for (int i = shape.bsColixSet.nextSetBit(0); i >= 0; i = shape.bsColixSet 1090 .nextSetBit(i + 1)) { 1091 short colix = bonds[i].colix; 1092 if ((colix & C.OPAQUE_MASK) == C.USE_PALETTE) 1093 BSUtil.setMapBitSet(temp, i, i, Shape.getColorCommand("bonds", 1094 PAL.CPK.id, colix, shape.translucentAllowed)); 1095 else 1096 BSUtil.setMapBitSet(temp, i, i, Shape.getColorCommandUnk("bonds", 1097 colix, shape.translucentAllowed)); 1098 } 1099 1100 String s = getCommands(temp, null, "select BONDS") + "\n" 1101 + (haveTainted ? getCommands(temp2, null, "select BONDS") + "\n" : ""); 1102 clearTemp(); 1103 return s; 1104 } 1105 clearTemp()1106 private void clearTemp() { 1107 temp.clear(); 1108 temp2.clear(); 1109 } 1110 getShapeState(Shape shape)1111 private String getShapeState(Shape shape) { 1112 String s; 1113 switch (shape.shapeID) { 1114 case JC.SHAPE_AXES: 1115 s = getAxesState((Axes) shape); 1116 break; 1117 case JC.SHAPE_UCCAGE: 1118 if (!vwr.ms.haveUnitCells) 1119 return ""; 1120 String st = s = getFontLineShapeState((FontLineShape) shape); 1121 int iAtom = vwr.am.getUnitCellAtomIndex(); 1122 if (iAtom >= 0) 1123 s += " unitcell ({" + iAtom + "});\n"; 1124 SymmetryInterface uc = vwr.getCurrentUnitCell(); 1125 if (uc != null) { 1126 s += uc.getUnitCellState(); 1127 s += st; // needs to be after this state as well. 1128 } 1129 break; 1130 case JC.SHAPE_BBCAGE: 1131 s = getFontLineShapeState((FontLineShape) shape); 1132 break; 1133 case JC.SHAPE_FRANK: 1134 s = getFontState(shape.myType, ((Frank) shape).baseFont3d); 1135 break; 1136 case JC.SHAPE_MEASURES: 1137 s = getMeasurementState((Measures) shape); 1138 break; 1139 case JC.SHAPE_STARS: 1140 case JC.SHAPE_VECTORS: 1141 s = getAtomShapeState((AtomShape) shape); 1142 break; 1143 case JC.SHAPE_STICKS: 1144 s = getBondState((Sticks) shape); 1145 break; 1146 case JC.SHAPE_ECHO: 1147 Echo es = (Echo) shape; 1148 SB sb = new SB(); 1149 sb.append("\n set echo off;\n"); 1150 for (Text t : es.objects.values()) { 1151 sb.append(getTextState(t)); 1152 if (t.hidden) 1153 sb.append(" set echo ID ").append(PT.esc(t.target)) 1154 .append(" hidden;\n"); 1155 } 1156 s = sb.toString(); 1157 break; 1158 case JC.SHAPE_HALOS: 1159 Halos hs = (Halos) shape; 1160 s = getAtomShapeState(hs) 1161 + (hs.colixSelection == C.USE_PALETTE ? "" 1162 : hs.colixSelection == C.INHERIT_ALL ? " color SelectionHalos NONE;\n" 1163 : Shape.getColorCommandUnk("selectionHalos", 1164 hs.colixSelection, hs.translucentAllowed) + ";\n"); 1165 if (hs.bsHighlight != null) 1166 s += " set highlight " 1167 + Escape.eBS(hs.bsHighlight) 1168 + "; " 1169 + Shape.getColorCommandUnk("highlight", hs.colixHighlight, 1170 hs.translucentAllowed) + ";\n"; 1171 break; 1172 case JC.SHAPE_HOVER: 1173 clearTemp(); 1174 Hover h = (Hover) shape; 1175 if (h.atomFormats != null) 1176 for (int i = vwr.ms.ac; --i >= 0;) 1177 if (h.atomFormats[i] != null) 1178 BSUtil.setMapBitSet(temp, i, i, 1179 "set hoverLabel " + PT.esc(h.atomFormats[i])); 1180 s = "\n hover " + PT.esc((h.labelFormat == null ? "" : h.labelFormat)) 1181 + ";\n" + getCommands(temp, null, "select"); 1182 clearTemp(); 1183 break; 1184 case JC.SHAPE_LABELS: 1185 Labels l = (Labels) shape; 1186 if (!l.isActive || l.bsSizeSet == null) 1187 return ""; 1188 clearTemp(); 1189 for (int i = l.bsSizeSet.nextSetBit(0); i >= 0; i = l.bsSizeSet 1190 .nextSetBit(i + 1)) { 1191 Text t = l.getLabel(i); 1192 String cmd = "label "; 1193 if (t == null) { 1194 cmd += PT.esc(l.formats[i]); 1195 } else { 1196 cmd += PT.esc(t.textUnformatted); 1197 if (t.pymolOffset != null) 1198 cmd += ";set labelOffset " + Escape.eAF(t.pymolOffset); 1199 } 1200 BSUtil.setMapBitSet(temp, i, i, cmd); 1201 if (l.bsColixSet != null && l.bsColixSet.get(i)) 1202 BSUtil.setMapBitSet(temp2, i, i, Shape.getColorCommand("label", 1203 l.paletteIDs[i], l.colixes[i], l.translucentAllowed)); 1204 if (l.bsBgColixSet != null && l.bsBgColixSet.get(i)) 1205 BSUtil.setMapBitSet(temp2, i, i, 1206 "background label " + Shape.encodeColor(l.bgcolixes[i])); 1207 Text text = l.getLabel(i); 1208 float sppm = (text != null ? text.scalePixelsPerMicron : 0); 1209 if (sppm > 0) 1210 BSUtil.setMapBitSet(temp2, i, i, "set labelScaleReference " 1211 + (10000f / sppm)); 1212 if (l.offsets != null && l.offsets.length > i) { 1213 int offsetFull = l.offsets[i]; 1214 BSUtil.setMapBitSet( 1215 temp2, 1216 i, 1217 i, 1218 "set " 1219 + (JC.isOffsetAbsolute(offsetFull) ? "labelOffsetAbsolute " 1220 : "labelOffset ") + JC.getXOffset(offsetFull) + " " 1221 + JC.getYOffset(offsetFull)); 1222 String align = JC.getHorizAlignmentName(offsetFull >> 2); 1223 String pointer = JC.getPointerName(offsetFull); 1224 if (pointer.length() > 0) 1225 BSUtil.setMapBitSet(temp2, i, i, "set labelPointer " + pointer); 1226 if ((offsetFull & JC.LABEL_ZPOS_FRONT) != 0) 1227 BSUtil.setMapBitSet(temp2, i, i, "set labelFront"); 1228 else if ((offsetFull & JC.LABEL_ZPOS_GROUP) != 0) 1229 BSUtil.setMapBitSet(temp2, i, i, "set labelGroup"); 1230 // labelAlignment must come last, so we put it in a separate hash 1231 // table 1232 if (align.length() > 0) 1233 BSUtil.setMapBitSet(temp3, i, i, "set labelAlignment " + align); 1234 } 1235 1236 if (l.mads != null && l.mads[i] < 0) 1237 BSUtil.setMapBitSet(temp2, i, i, "set toggleLabel"); 1238 if (l.bsFontSet != null && l.bsFontSet.get(i)) 1239 BSUtil.setMapBitSet(temp2, i, i, 1240 Shape.getFontCommand("label", Font.getFont3D(l.fids[i]))); 1241 } 1242 s = getCommands(temp, temp2, "select") 1243 + getCommands(null, temp3, "select"); 1244 temp3.clear(); 1245 clearTemp(); 1246 break; 1247 case JC.SHAPE_BALLS: 1248 clearTemp(); 1249 int ac = vwr.ms.ac; 1250 Atom[] atoms = vwr.ms.at; 1251 Balls balls = (Balls) shape; 1252 short[] colixes = balls.colixes; 1253 byte[] pids = balls.paletteIDs; 1254 float r = 0; 1255 for (int i = 0; i < ac; i++) { 1256 if (atoms[i] != null && shape.bsSizeSet != null && shape.bsSizeSet.get(i)) { 1257 if ((r = atoms[i].madAtom) < 0) 1258 BSUtil.setMapBitSet(temp, i, i, "Spacefill on"); 1259 else 1260 BSUtil.setMapBitSet(temp, i, i, "Spacefill " + PT.escF(r / 2000f)); 1261 } 1262 if (shape.bsColixSet != null && shape.bsColixSet.get(i)) { 1263 byte pid = atoms[i].paletteID; 1264 if (pid != PAL.CPK.id || C.isColixTranslucent(atoms[i].colixAtom)) 1265 BSUtil.setMapBitSet(temp, i, i, Shape.getColorCommand("atoms", pid, 1266 atoms[i].colixAtom, shape.translucentAllowed)); 1267 if (colixes != null && i < colixes.length) 1268 BSUtil.setMapBitSet(temp2, i, i, Shape.getColorCommand("balls", 1269 pids[i], colixes[i], shape.translucentAllowed)); 1270 } 1271 } 1272 s = getCommands(temp, temp2, "select"); 1273 clearTemp(); 1274 break; 1275 default: 1276 s = shape.getShapeState(); 1277 break; 1278 } 1279 return s; 1280 } 1281 getFontLineShapeState(FontLineShape shape)1282 private String getFontLineShapeState(FontLineShape shape) { 1283 String s = getFontState(shape.myType, shape.font3d); 1284 if (shape.tickInfos == null) 1285 return s; 1286 boolean isOff = (s.indexOf(" off") >= 0); 1287 SB sb = new SB(); 1288 sb.append(s); 1289 for (int i = 0; i < 4; i++) 1290 if (shape.tickInfos[i] != null) 1291 appendTickInfo(shape.myType, sb, shape.tickInfos[i]); 1292 if (isOff) 1293 sb.append(" " + shape.myType + " off;\n"); 1294 return sb.toString(); 1295 } 1296 getAxesState(Axes axes)1297 private String getAxesState(Axes axes) { 1298 SB sb = new SB(); 1299 sb.append(getFontLineShapeState(axes)); 1300 sb.append(" axes scale ").appendF(vwr.getFloat(T.axesscale)).append(";\n"); 1301 if (axes.fixedOrigin != null) 1302 sb.append(" axes center ") 1303 .append(Escape.eP(axes.fixedOrigin)).append(";\n"); 1304 P3 axisXY = axes.axisXY; 1305 if (axisXY.z != 0) 1306 sb.append(" axes position [") 1307 .appendI((int) axisXY.x).append(" ") 1308 .appendI((int) axisXY.y).append(" ") 1309 .append(axisXY.z < 0 ? " %" : "").append("];\n"); 1310 String[] labels = axes.labels; 1311 if (labels != null) { 1312 sb.append(" axes labels "); 1313 for (int i = 0; i < labels.length; i++) 1314 if (labels[i] != null) 1315 sb.append(PT.esc(labels[i])).append(" "); 1316 sb.append(";\n"); 1317 } 1318 if (axes.axisType != null) { 1319 sb.append(" axes type " + PT.esc(axes.axisType)); 1320 } 1321 return sb.toString(); 1322 } 1323 1324 1325 @Override 1326 public String getAtomShapeState(AtomShape shape) { 1327 // called also by Polyhedra 1328 if (!shape.isActive) 1329 return ""; 1330 clearTemp(); 1331 String type = JC.shapeClassBases[shape.shapeID]; 1332 boolean isVector = (shape.shapeID == JC.SHAPE_VECTORS); 1333 int mad; 1334 if (shape.bsSizeSet != null) 1335 for (int i = shape.bsSizeSet.nextSetBit(0); i >= 0; i = shape.bsSizeSet 1336 .nextSetBit(i + 1)) 1337 BSUtil.setMapBitSet(temp, i, i, type 1338 + " " + ((mad = shape.mads[i]) < 0 ? (isVector && mad < -1 ? "" + -mad : "on") : PT.escF(mad / 2000f))); 1339 if (shape.bsColixSet != null) 1340 for (int i = shape.bsColixSet.nextSetBit(0); i >= 0; i = shape.bsColixSet 1341 .nextSetBit(i + 1)) 1342 BSUtil.setMapBitSet(temp2, i, i, Shape.getColorCommand(type, 1343 shape.paletteIDs[i], shape.colixes[i], shape.translucentAllowed)); 1344 String s = getCommands(temp, temp2, "select"); 1345 clearTemp(); 1346 return s; 1347 } 1348 1349 private String getTextState(Text t) { 1350 SB s = new SB(); 1351 String text = t.text; 1352 if (text == null || !t.isEcho || t.target.equals("error")) 1353 return ""; 1354 //set echo top left 1355 //set echo myecho x y 1356 //echo ..... 1357 boolean isImage = (t.image != null); 1358 // if (isDefine) { 1359 String strOff = null; 1360 String echoCmd = "set echo ID " + PT.esc(t.target); 1361 switch (t.valign) { 1362 case JC.ECHO_XY: 1363 if (t.movableXPercent == Integer.MAX_VALUE 1364 || t.movableYPercent == Integer.MAX_VALUE) { 1365 strOff = (t.movableXPercent == Integer.MAX_VALUE ? t.movableX + " " 1366 : t.movableXPercent + "% ") 1367 + (t.movableYPercent == Integer.MAX_VALUE ? t.movableY + "" 1368 : t.movableYPercent + "%"); 1369 } else { 1370 strOff = "[" + t.movableXPercent + " " + t.movableYPercent + "%]"; 1371 } 1372 //$FALL-THROUGH$ 1373 case JC.ECHO_XYZ: 1374 if (strOff == null) 1375 strOff = Escape.eP(t.xyz); 1376 s.append(" ").append(echoCmd).append(" ").append(strOff); 1377 if (t.align != JC.TEXT_ALIGN_LEFT) 1378 s.append("; ").append(echoCmd).append(" ").append( 1379 JC.getHorizAlignmentName(t.align)); 1380 break; 1381 default: 1382 s.append(" set echo ").append(JC.getEchoName(t.valign)).append(" ") 1383 .append(JC.getHorizAlignmentName(t.align)); 1384 } 1385 if (t.movableZPercent != Integer.MAX_VALUE) 1386 s.append("; ").append(echoCmd).append(" depth ").appendI( 1387 t.movableZPercent); 1388 if (isImage) 1389 s.append("; ").append(echoCmd).append(" IMAGE /*file*/"); 1390 else 1391 s.append("; echo "); 1392 s.append(PT.esc(text)); // was textUnformatted, but that is not really the STATE 1393 s.append(";\n"); 1394 if (isImage && t.imageScale != 1) 1395 s.append(" ").append(echoCmd).append(" scale ").appendF(t.imageScale) 1396 .append(";\n"); 1397 if (t.script != null) 1398 s.append(" ").append(echoCmd).append(" script ").append( 1399 PT.esc(t.script)).append(";\n"); 1400 if (t.modelIndex >= 0) 1401 s.append(" ").append(echoCmd).append(" model ").append( 1402 vwr.getModelNumberDotted(t.modelIndex)).append(";\n"); 1403 if (t.pointerPt != null) { 1404 s.append(" ").append(echoCmd).append(" point ").append( 1405 t.pointerPt instanceof Atom ? "({" + ((Atom) t.pointerPt).i 1406 + "})" : Escape.eP(t.pointerPt)).append(";\n"); 1407 } 1408 if (t.pymolOffset != null) { 1409 s.append(" ").append(echoCmd).append(" offset ").append( 1410 Escape.escapeFloatA(t.pymolOffset, true)).append(";\n"); 1411 } 1412 // } 1413 //isDefine and target==top: do all 1414 //isDefine and target!=top: just start 1415 //!isDefine and target==top: do nothing 1416 //!isDefine and target!=top: do just this 1417 //fluke because top is defined with default font 1418 //in initShape(), so we MUST include its font def here 1419 // if (isDefine != target.equals("top")) 1420 // return s.toString(); 1421 // these may not change much: 1422 t.appendFontCmd(s); 1423 s.append("; color echo"); 1424 if (C.isColixTranslucent(t.colix)) 1425 s.append(C.getColixTranslucencyLabel(t.colix)); 1426 s.append(" ").append(C.getHexCode(t.colix)); 1427 if (t.bgcolix != 0) { 1428 s.append("; color echo background "); 1429 if (C.isColixTranslucent(t.bgcolix)) 1430 s.append(C.getColixTranslucencyLabel(t.bgcolix)).append(" "); 1431 s.append(C.getHexCode(t.bgcolix)); 1432 } 1433 s.append(";\n"); 1434 return s.toString(); 1435 } 1436 1437 @Override 1438 String getAllSettings(String prefix) { 1439 GlobalSettings g = vwr.g; 1440 SB commands = new SB(); 1441 String[] list = new String[g.htBooleanParameterFlags.size() 1442 + g.htNonbooleanParameterValues.size() + g.htUserVariables.size()]; 1443 //booleans 1444 int n = 0; 1445 String _prefix = "_" + prefix; 1446 for (String key : g.htBooleanParameterFlags.keySet()) { 1447 if (prefix == null || key.indexOf(prefix) == 0 1448 || key.indexOf(_prefix) == 0) 1449 list[n++] = (key.indexOf("_") == 0 ? key + " = " : "set " + key + " ") 1450 + g.htBooleanParameterFlags.get(key); 1451 } 1452 //save as _xxxx if you don't want "set" to be there first 1453 for (String key : g.htNonbooleanParameterValues.keySet()) { 1454 if (key.charAt(0) != '@' 1455 && (prefix == null || key.indexOf(prefix) == 0 || key 1456 .indexOf(_prefix) == 0)) { 1457 Object value = g.htNonbooleanParameterValues.get(key); 1458 if (value instanceof String) 1459 value = chop(PT.esc((String) value)); 1460 list[n++] = (key.indexOf("_") == 0 ? key + " = " : "set " + key + " ") 1461 + value; 1462 } 1463 } 1464 for (String key : g.htUserVariables.keySet()) { 1465 if (prefix == null || key.indexOf(prefix) == 0) { 1466 SV value = g.htUserVariables.get(key); 1467 String s = value.escape(); 1468 list[n++] = key + " " + (key.startsWith("@") ? "" : "= ") 1469 + (value.tok == T.string ? chop(PT.esc(s)) : s); 1470 } 1471 } 1472 Arrays.sort(list, 0, n); 1473 for (int i = 0; i < n; i++) 1474 if (list[i] != null) 1475 app(commands, list[i]); 1476 commands.append("\n"); 1477 return commands.toString(); 1478 } 1479 1480 private static String chop(String s) { 1481 int len = s.length(); 1482 if (len < 512) 1483 return s; 1484 SB sb = new SB(); 1485 String sep = "\"\\\n + \""; 1486 int pt = 0; 1487 for (int i = 72; i < len; pt = i, i += 72) { 1488 while (s.charAt(i - 1) == '\\') 1489 i++; 1490 sb.append((pt == 0 ? "" : sep)).append(s.substring(pt, i)); 1491 } 1492 sb.append(sep).append(s.substring(pt, len)); 1493 return sb.toString(); 1494 } 1495 1496 @Override 1497 String getFunctionCalls(String f) { 1498 if (f == null) 1499 f = ""; 1500 SB s = new SB(); 1501 int pt = f.indexOf("*"); 1502 boolean isGeneric = (pt >= 0); 1503 boolean isStatic = (f.indexOf("static_") == 0); 1504 boolean namesOnly = (f.equalsIgnoreCase("names") || f 1505 .equalsIgnoreCase("static_names")); 1506 if (namesOnly) 1507 f = ""; 1508 if (isGeneric) 1509 f = f.substring(0, pt); 1510 f = f.toLowerCase(); 1511 if (isStatic || f.length() == 0) 1512 addFunctions(s, Viewer.staticFunctions, f, isGeneric, namesOnly); 1513 if (!isStatic || f.length() == 0) 1514 addFunctions(s, vwr.localFunctions, f, isGeneric, namesOnly); 1515 return s.toString(); 1516 } 1517 1518 private void addFunctions(SB s, Map<String, JmolScriptFunction> ht, String selectedFunction, 1519 boolean isGeneric, boolean namesOnly) { 1520 String[] names = new String[ht.size()]; 1521 int n = 0; 1522 for (String name : ht.keySet()) 1523 if (selectedFunction.length() == 0 && !name.startsWith("_") 1524 || name.equalsIgnoreCase(selectedFunction) || isGeneric 1525 && name.toLowerCase().indexOf(selectedFunction) == 0) 1526 names[n++] = name; 1527 Arrays.sort(names, 0, n); 1528 for (int i = 0; i < n; i++) { 1529 JmolScriptFunction f = ht.get(names[i]); 1530 s.append(namesOnly ? f.getSignature() : f.toString()); 1531 s.appendC('\n'); 1532 } 1533 } 1534 1535 private static boolean isTainted(BS[] tainted, int atomIndex, int type) { 1536 return (tainted != null && tainted[type] != null && tainted[type] 1537 .get(atomIndex)); 1538 } 1539 1540 @Override 1541 String getAtomicPropertyState(int taintWhat, BS bsSelected) { 1542 if (!vwr.g.preserveState) 1543 return ""; 1544 BS bs; 1545 SB commands = new SB(); 1546 for (int type = 0; type < AtomCollection.TAINT_MAX; type++) 1547 if (taintWhat < 0 || type == taintWhat) 1548 if ((bs = (bsSelected != null ? bsSelected : vwr 1549 .ms.getTaintedAtoms(type))) != null) 1550 getAtomicPropertyStateBuffer(commands, type, bs, null, null); 1551 return commands.toString(); 1552 } 1553 1554 @Override 1555 void getAtomicPropertyStateBuffer(SB commands, int type, BS bs, 1556 String label, float[] fData) { 1557 if (!vwr.g.preserveState) 1558 return; 1559 // see setAtomData() 1560 SB s = new SB(); 1561 String dataLabel = (label == null ? AtomCollection.userSettableValues[type] 1562 : label) 1563 + " set"; 1564 int n = 0; 1565 boolean isDefault = (type == AtomCollection.TAINT_COORD); 1566 Atom[] atoms = vwr.ms.at; 1567 BS[] tainted = vwr.ms.tainted; 1568 if (bs != null) 1569 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { 1570 if (atoms[i] == null || atoms[i].isDeleted()) 1571 continue; 1572 s.appendI(i + 1).append(" ").append(atoms[i].getElementSymbol()) 1573 .append(" ").append(atoms[i].getInfo().replace(' ', '_')).append( 1574 " "); 1575 switch (type) { 1576 case AtomCollection.TAINT_MAX: 1577 if (i < fData.length) // when data are appended, the array may not 1578 // extend that far 1579 s.appendF(fData[i]); 1580 break; 1581 case AtomCollection.TAINT_ATOMNO: 1582 s.appendI(atoms[i].getAtomNumber()); 1583 break; 1584 case AtomCollection.TAINT_CHAIN: 1585 s.append(atoms[i].getChainIDStr()); 1586 break; 1587 case AtomCollection.TAINT_RESNO: 1588 s.appendI(atoms[i].group.getResno()); 1589 break; 1590 case AtomCollection.TAINT_SEQID: 1591 s.appendI(atoms[i].getSeqID()); 1592 break; 1593 case AtomCollection.TAINT_ATOMNAME: 1594 s.append(atoms[i].getAtomName()); 1595 break; 1596 case AtomCollection.TAINT_ATOMTYPE: 1597 s.append(atoms[i].getAtomType()); 1598 break; 1599 case AtomCollection.TAINT_COORD: 1600 if (isTainted(tainted, i, AtomCollection.TAINT_COORD)) 1601 isDefault = false; 1602 s.appendF(atoms[i].x).append(" ").appendF(atoms[i].y).append(" ") 1603 .appendF(atoms[i].z); 1604 break; 1605 case AtomCollection.TAINT_VIBRATION: 1606 Vibration v = atoms[i].getVibrationVector(); 1607 if (v == null) 1608 s.append("0 0 0"); 1609 else if (Float.isNaN(v.modScale)) 1610 s.appendF(v.x).append(" ").appendF(v.y).append(" ").appendF(v.z); 1611 else 1612 s.appendF(PT.FLOAT_MIN_SAFE).append(" ").appendF(PT.FLOAT_MIN_SAFE).append(" ").appendF(v.modScale); 1613 break; 1614 case AtomCollection.TAINT_ELEMENT: 1615 s.appendI(atoms[i].getAtomicAndIsotopeNumber()); 1616 break; 1617 case AtomCollection.TAINT_FORMALCHARGE: 1618 s.appendI(atoms[i].getFormalCharge()); 1619 break; 1620 case AtomCollection.TAINT_BONDINGRADIUS: 1621 s.appendF(atoms[i].getBondingRadius()); 1622 break; 1623 case AtomCollection.TAINT_OCCUPANCY: 1624 s.appendI(atoms[i].getOccupancy100()); 1625 break; 1626 case AtomCollection.TAINT_PARTIALCHARGE: 1627 s.appendF(atoms[i].getPartialCharge()); 1628 break; 1629 case AtomCollection.TAINT_TEMPERATURE: 1630 s.appendF(atoms[i].getBfactor100() / 100f); 1631 break; 1632 case AtomCollection.TAINT_VALENCE: 1633 s.appendI(atoms[i].getValence()); 1634 break; 1635 case AtomCollection.TAINT_VANDERWAALS: 1636 s.appendF(atoms[i].getVanderwaalsRadiusFloat(vwr, VDW.AUTO)); 1637 break; 1638 } 1639 s.append(" ;\n"); 1640 ++n; 1641 } 1642 if (n == 0) 1643 return; 1644 if (isDefault) 1645 dataLabel += "(default)"; 1646 commands.append("\n DATA \"" + dataLabel + "\"\n").appendI(n).append( 1647 " ;\nJmol Property Data Format 1 -- Jmol ").append( 1648 Viewer.getJmolVersion()).append(";\n"); 1649 commands.appendSB(s); 1650 commands.append(" end \"" + dataLabel + "\";\n"); 1651 } 1652 1653 1654 ///////////////////////////////// undo/redo functions ///////////////////// 1655 1656 1657 @Override 1658 void undoMoveAction(int action, int n) { 1659 switch (action) { 1660 case T.undomove: 1661 case T.redomove: 1662 switch (n) { 1663 case -2: 1664 vwr.undoClear(); 1665 break; 1666 case -1: 1667 (action == T.undomove ? vwr.actionStates : vwr.actionStatesRedo) 1668 .clear(); 1669 break; 1670 case 0: 1671 n = Integer.MAX_VALUE; 1672 //$FALL-THROUGH$ 1673 default: 1674 if (n > MAX_ACTION_UNDO) 1675 n = (action == T.undomove ? vwr.actionStates 1676 : vwr.actionStatesRedo).size(); 1677 for (int i = 0; i < n; i++) 1678 undoMoveActionClear(0, action, true); 1679 } 1680 break; 1681 } 1682 } 1683 1684 @Override 1685 void undoMoveActionClear(int taintedAtom, int type, boolean clearRedo) { 1686 // called by actionManager 1687 if (!vwr.g.preserveState) 1688 return; 1689 int modelIndex = (taintedAtom >= 0 ? vwr.ms.at[taintedAtom].mi 1690 : vwr.ms.mc - 1); 1691 //System.out.print("undoAction " + type + " " + taintedAtom + " modelkit?" 1692 // + modelSet.models[modelIndex].isModelkit()); 1693 //System.out.println(" " + type + " size=" + actionStates.size() + " " 1694 // + +actionStatesRedo.size()); 1695 switch (type) { 1696 case T.redomove: 1697 case T.undomove: 1698 // from MouseManager 1699 // CTRL-Z: type = 1 UNDO 1700 // CTRL-Y: type = -1 REDO 1701 vwr.stopMinimization(); 1702 String s = ""; 1703 Lst<String> list1; 1704 Lst<String> list2; 1705 switch (type) { 1706 default: 1707 case T.undomove: 1708 list1 = vwr.actionStates; 1709 list2 = vwr.actionStatesRedo; 1710 break; 1711 case T.redomove: 1712 list1 = vwr.actionStatesRedo; 1713 list2 = vwr.actionStates; 1714 if (vwr.actionStatesRedo.size() == 1) 1715 return; 1716 break; 1717 } 1718 if (list1.size() == 0 || undoWorking) 1719 return; 1720 undoWorking = true; 1721 list2.add(0, list1.removeItemAt(0)); 1722 s = vwr.actionStatesRedo.get(0); 1723 if (type == T.undomove && list2.size() == 1) { 1724 // must save current state, coord, etc. 1725 // but this destroys actionStatesRedo 1726 int[] pt = new int[] { 1 }; 1727 type = PT.parseIntNext(s, pt); 1728 taintedAtom = PT.parseIntNext(s, pt); 1729 undoMoveActionClear(taintedAtom, type, false); 1730 } 1731 //System.out.println("redo type = " + type + " size=" + actionStates.size() 1732 // + " " + +actionStatesRedo.size()); 1733 if (vwr.ms.am[modelIndex].isModelKit 1734 || s.indexOf("zap ") < 0) { 1735 if (Logger.debugging) 1736 vwr.log(s); 1737 vwr.evalStringQuiet(s); 1738 } else { 1739 // if it's not modelkit mode and we are trying to do a zap, then ignore 1740 // and clear all action states. 1741 vwr.actionStates.clear(); 1742 } 1743 break; 1744 default: 1745 if (undoWorking && clearRedo) 1746 return; 1747 undoWorking = true; 1748 BS bs; 1749 SB sb = new SB(); 1750 sb.append("#" + type + " " + taintedAtom + " " + (new Date()) + "\n"); 1751 if (taintedAtom >= 0) { 1752 bs = vwr.getModelUndeletedAtomsBitSet(modelIndex); 1753 vwr.ms.taintAtoms(bs, type); 1754 sb.append(getAtomicPropertyState(-1, null)); 1755 } else { 1756 bs = vwr.getModelUndeletedAtomsBitSet(modelIndex); 1757 sb.append("zap "); 1758 sb.append(Escape.eBS(bs)).append(";"); 1759 getInlineData(sb, vwr.getModelExtract(bs, false, true, 1760 "MOL"), true, null, null); 1761 sb.append("set refreshing false;").append( 1762 vwr.acm.getPickingState()).append( 1763 vwr.tm.getMoveToText(0, false)).append( 1764 "set refreshing true;"); 1765 1766 } 1767 if (clearRedo) { 1768 vwr.actionStates.add(0, sb.toString()); 1769 vwr.actionStatesRedo.clear(); 1770 } else { 1771 vwr.actionStatesRedo.add(1, sb.toString()); 1772 } 1773 if (vwr.actionStates.size() == MAX_ACTION_UNDO) { 1774 vwr.actionStates.removeItemAt(MAX_ACTION_UNDO - 1); 1775 } 1776 } 1777 undoWorking = !clearRedo; 1778 } 1779 1780 private boolean undoWorking = false; 1781 private final static int MAX_ACTION_UNDO = 100; 1782 1783 1784 } 1785