PageRenderTime 37ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/br.ufes.inf.nemo.oled/src/edu/mit/csail/sdg/alloy4whole/SimpleGUICustom.java

https://github.com/petrux/OLED
Java | 2102 lines | 1587 code | 204 blank | 311 comment | 332 complexity | 4a33cd158b6068263ff03ae82327f508 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. package edu.mit.csail.sdg.alloy4whole;
  2. /**
  3. * Alloy Analyzer 4 -- Copyright (c) 2006-2009, Felix Chang
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
  6. * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
  7. * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  11. *
  12. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  13. * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  14. * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
  15. * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  16. *
  17. */
  18. import static edu.mit.csail.sdg.alloy4.OurUtil.menu;
  19. import static edu.mit.csail.sdg.alloy4.OurUtil.menuItem;
  20. import static java.awt.event.KeyEvent.VK_A;
  21. import static java.awt.event.KeyEvent.VK_ALT;
  22. import static java.awt.event.KeyEvent.VK_E;
  23. import static java.awt.event.KeyEvent.VK_PAGE_DOWN;
  24. import static java.awt.event.KeyEvent.VK_PAGE_UP;
  25. import static java.awt.event.KeyEvent.VK_SHIFT;
  26. import java.awt.BorderLayout;
  27. import java.awt.Color;
  28. import java.awt.Container;
  29. import java.awt.Font;
  30. import java.awt.GraphicsEnvironment;
  31. import java.awt.Toolkit;
  32. import java.awt.event.ComponentEvent;
  33. import java.awt.event.ComponentListener;
  34. import java.io.File;
  35. import java.io.FileInputStream;
  36. import java.io.IOException;
  37. import java.io.InputStream;
  38. import java.io.ObjectInputStream;
  39. import java.lang.reflect.Method;
  40. import java.util.ArrayList;
  41. import java.util.Arrays;
  42. import java.util.Date;
  43. import java.util.LinkedHashMap;
  44. import java.util.List;
  45. import java.util.Locale;
  46. import java.util.Map;
  47. import java.util.Random;
  48. import java.util.Scanner;
  49. import java.util.Set;
  50. import java.util.prefs.Preferences;
  51. import javax.swing.Box;
  52. import javax.swing.Icon;
  53. import javax.swing.JButton;
  54. import javax.swing.JCheckBox;
  55. import javax.swing.JComboBox;
  56. import javax.swing.JEditorPane;
  57. import javax.swing.JFrame;
  58. import javax.swing.JLabel;
  59. import javax.swing.JMenu;
  60. import javax.swing.JMenuBar;
  61. import javax.swing.JMenuItem;
  62. import javax.swing.JPanel;
  63. import javax.swing.JScrollPane;
  64. import javax.swing.JSeparator;
  65. import javax.swing.JSplitPane;
  66. import javax.swing.JTextArea;
  67. import javax.swing.JTextField;
  68. import javax.swing.JToolBar;
  69. import javax.swing.KeyStroke;
  70. import javax.swing.SwingUtilities;
  71. import javax.swing.WindowConstants;
  72. import javax.swing.border.EmptyBorder;
  73. import javax.swing.border.LineBorder;
  74. import javax.swing.event.HyperlinkEvent;
  75. import javax.swing.event.HyperlinkListener;
  76. import javax.swing.text.html.HTMLDocument;
  77. import kodkod.engine.fol2sat.HigherOrderDeclException;
  78. import edu.mit.csail.sdg.alloy4.A4Reporter;
  79. import edu.mit.csail.sdg.alloy4.Computer;
  80. import edu.mit.csail.sdg.alloy4.Err;
  81. import edu.mit.csail.sdg.alloy4.ErrorFatal;
  82. import edu.mit.csail.sdg.alloy4.ErrorType;
  83. import edu.mit.csail.sdg.alloy4.Listener;
  84. import edu.mit.csail.sdg.alloy4.MacUtil;
  85. import edu.mit.csail.sdg.alloy4.OurAntiAlias;
  86. import edu.mit.csail.sdg.alloy4.OurBorder;
  87. import edu.mit.csail.sdg.alloy4.OurCombobox;
  88. import edu.mit.csail.sdg.alloy4.OurDialog;
  89. import edu.mit.csail.sdg.alloy4.OurSyntaxWidget;
  90. import edu.mit.csail.sdg.alloy4.OurTabbedSyntaxWidget;
  91. import edu.mit.csail.sdg.alloy4.OurTree;
  92. import edu.mit.csail.sdg.alloy4.OurUtil;
  93. import edu.mit.csail.sdg.alloy4.Pair;
  94. import edu.mit.csail.sdg.alloy4.Pos;
  95. import edu.mit.csail.sdg.alloy4.Runner;
  96. import edu.mit.csail.sdg.alloy4.Subprocess;
  97. import edu.mit.csail.sdg.alloy4.Util;
  98. import edu.mit.csail.sdg.alloy4.Util.BooleanPref;
  99. import edu.mit.csail.sdg.alloy4.Util.IntPref;
  100. import edu.mit.csail.sdg.alloy4.Util.StringPref;
  101. import edu.mit.csail.sdg.alloy4.Version;
  102. import edu.mit.csail.sdg.alloy4.WorkerEngineCustom;
  103. import edu.mit.csail.sdg.alloy4.WorkerEngineCustom.WorkerCallbackCustom;
  104. import edu.mit.csail.sdg.alloy4.XMLNode;
  105. import edu.mit.csail.sdg.alloy4compiler.ast.Browsable;
  106. import edu.mit.csail.sdg.alloy4compiler.ast.Command;
  107. import edu.mit.csail.sdg.alloy4compiler.ast.Expr;
  108. import edu.mit.csail.sdg.alloy4compiler.ast.ExprVar;
  109. import edu.mit.csail.sdg.alloy4compiler.ast.Module;
  110. import edu.mit.csail.sdg.alloy4compiler.ast.Sig;
  111. import edu.mit.csail.sdg.alloy4compiler.ast.Sig.Field;
  112. import edu.mit.csail.sdg.alloy4compiler.parser.CompUtil;
  113. import edu.mit.csail.sdg.alloy4compiler.sim.SimInstance;
  114. import edu.mit.csail.sdg.alloy4compiler.sim.SimTuple;
  115. import edu.mit.csail.sdg.alloy4compiler.sim.SimTupleset;
  116. import edu.mit.csail.sdg.alloy4compiler.translator.A4Options;
  117. import edu.mit.csail.sdg.alloy4compiler.translator.A4Options.SatSolver;
  118. import edu.mit.csail.sdg.alloy4compiler.translator.A4Solution;
  119. import edu.mit.csail.sdg.alloy4compiler.translator.A4SolutionReader;
  120. import edu.mit.csail.sdg.alloy4compiler.translator.A4Tuple;
  121. import edu.mit.csail.sdg.alloy4compiler.translator.A4TupleSet;
  122. import edu.mit.csail.sdg.alloy4viz.VizGUICustom;
  123. import edu.mit.csail.sdg.alloy4whole.SimpleReporterCustom.SimpleCallback1;
  124. import edu.mit.csail.sdg.alloy4whole.SimpleReporterCustom.SimpleTask1;
  125. import edu.mit.csail.sdg.alloy4whole.SimpleReporterCustom.SimpleTask2;
  126. /** Simple graphical interface for accessing various features of the analyzer.
  127. *
  128. * <p> Except noted below, methods in this class can only be called by the AWT event thread.
  129. *
  130. * <p> The methods that might get called from other threads are:
  131. * <br> (1) the run() method in SatRunner is launched from a fresh thread
  132. * <br> (2) the run() method in the instance watcher (in constructor) is launched from a fresh thread
  133. */
  134. public final class SimpleGUICustom implements ComponentListener, Listener {
  135. /** The latest welcome screen; each time we update the welcome screen, we increment this number. */
  136. private static final int welcomeLevel = 2;
  137. // Verify that the graphics environment is set up
  138. static {
  139. try {
  140. GraphicsEnvironment.getLocalGraphicsEnvironment();
  141. } catch(Throwable ex) {
  142. System.err.println("Unable to start the graphical environment.");
  143. System.err.println("If you're on Mac OS X:");
  144. System.err.println(" Please make sure you are running as the current local user.");
  145. System.err.println("If you're on Linux or FreeBSD:");
  146. System.err.println(" Please make sure your X Windows is configured.");
  147. System.err.println(" You can verify this by typing \"xhost\"; it should not give an error message.");
  148. System.err.flush();
  149. /*System.exit(1);*/
  150. }
  151. }
  152. //======== The Preferences ======================================================================================//
  153. //======== Note: you must make sure each preference has a unique key ============================================//
  154. /** The list of allowable memory sizes. */
  155. private List<Integer> allowedMemorySizes;
  156. /** True if Alloy Analyzer should let warning be nonfatal. */
  157. private static final BooleanPref WarningNonfatal = new BooleanPref("WarningNonfatal");
  158. /** True if Alloy Analyzer should automatically visualize the latest instance. */
  159. private static final BooleanPref AutoVisualize = new BooleanPref("AutoVisualize");
  160. /** True if Alloy Analyzer should insist on antialias. */
  161. private static final BooleanPref AntiAlias = new BooleanPref("AntiAlias");
  162. /** True if Alloy Analyzer should record the raw Kodkod input and output. */
  163. private static final BooleanPref RecordKodkod = new BooleanPref("RecordKodkod");
  164. /** True if Alloy Analyzer should enable the new Implicit This name resolution. */
  165. private static final BooleanPref ImplicitThis = new BooleanPref("ImplicitThis");
  166. /** True if Alloy Analyzer should not report models that overflow. */
  167. private static final BooleanPref NoOverflow = new BooleanPref("NoOverflow");
  168. /** The latest X corrdinate of the Alloy Analyzer's main window. */
  169. private static final IntPref AnalyzerX = new IntPref("AnalyzerX",0,-1,65535);
  170. /** The latest Y corrdinate of the Alloy Analyzer's main window. */
  171. private static final IntPref AnalyzerY = new IntPref("AnalyzerY",0,-1,65535);
  172. /** The latest width of the Alloy Analyzer's main window. */
  173. private static final IntPref AnalyzerWidth = new IntPref("AnalyzerWidth",0,-1,65535);
  174. /** The latest height of the Alloy Analyzer's main window. */
  175. private static final IntPref AnalyzerHeight = new IntPref("AnalyzerHeight",0,-1,65535);
  176. /** The latest font size of the Alloy Analyzer. */
  177. private static final IntPref FontSize = new IntPref("FontSize",9,12,72);
  178. /** The latest font name of the Alloy Analyzer. */
  179. private static final StringPref FontName = new StringPref("FontName","Lucida Grande");
  180. /** The latest tab distance of the Alloy Analyzer. */
  181. private static final IntPref TabSize = new IntPref("TabSize",1,2,16);
  182. /** The latest welcome screen that the user has seen. */
  183. private static final IntPref Welcome = new IntPref("Welcome",0,0,1000);
  184. /** Whether syntax highlighting should be disabled or not. */
  185. private static final BooleanPref SyntaxDisabled = new BooleanPref("SyntaxHighlightingDisabled");
  186. /** The number of recursion unrolls. */
  187. private static final IntPref Unrolls = new IntPref("Unrolls", -1, -1, 3);
  188. /** The skolem depth. */
  189. private static final IntPref SkolemDepth = new IntPref("SkolemDepth3", 0, 1, 4);
  190. /** The unsat core minimization strategy. */
  191. private static final IntPref CoreMinimization = new IntPref("CoreMinimization",0,2,2);
  192. /** The unsat core granularity. */
  193. private static final IntPref CoreGranularity = new IntPref("CoreGranularity",0,0,3);
  194. /** The amount of memory (in M) to allocate for Kodkod and the SAT solvers. */
  195. private static final IntPref SubMemory = new IntPref("SubMemory",16,768,65535);
  196. /** The amount of stack (in K) to allocate for Kodkod and the SAT solvers. */
  197. private static final IntPref SubStack = new IntPref("SubStack",16,8192,65536);
  198. /** The first file in Alloy Analyzer's "open recent" list. */
  199. private static final StringPref Model0 = new StringPref("Model0");
  200. /** The second file in Alloy Analyzer's "open recent" list. */
  201. private static final StringPref Model1 = new StringPref("Model1");
  202. /** The third file in Alloy Analyzer's "open recent" list. */
  203. private static final StringPref Model2 = new StringPref("Model2");
  204. /** The fourth file in Alloy Analyzer's "open recent" list. */
  205. private static final StringPref Model3 = new StringPref("Model3");
  206. /** This enum defines the set of possible message verbosity levels. */
  207. private enum Verbosity {
  208. /** Level 0. */ DEFAULT("0", "low"),
  209. /** Level 1. */ VERBOSE("1", "medium"),
  210. /** Level 2. */ DEBUG("2", "high"),
  211. /** Level 3. */ FULLDEBUG("3", "debug only");
  212. /** Returns true if it is greater than or equal to "other". */
  213. @SuppressWarnings("unused")
  214. public boolean geq(Verbosity other) { return ordinal() >= other.ordinal(); }
  215. /** This is a unique String for this value; it should be kept consistent in future versions. */
  216. private final String id;
  217. /** This is the label that the toString() method will return. */
  218. private final String label;
  219. /** Constructs a new Verbosity value with the given id and label. */
  220. private Verbosity(String id, String label) { this.id=id; this.label=label; }
  221. /** Given an id, return the enum value corresponding to it (if there's no match, then return DEFAULT). */
  222. private static Verbosity parse(String id) {
  223. for(Verbosity vb: values()) if (vb.id.equals(id)) return vb;
  224. return DEFAULT;
  225. }
  226. /** Returns the human-readable label for this enum value. */
  227. @Override public final String toString() { return label; }
  228. /** Saves this value into the Java preference object. */
  229. private void set() { Preferences.userNodeForPackage(Util.class).put("Verbosity",id); }
  230. /** Reads the current value of the Java preference object (if it's not set, then return DEFAULT). */
  231. private static Verbosity get() { return parse(Preferences.userNodeForPackage(Util.class).get("Verbosity","")); }
  232. };
  233. //===================================================================================================//
  234. /** The JFrame for the main window. */
  235. public JFrame frame;
  236. /** The JFrame for the visualizer window. */
  237. private VizGUICustom viz;
  238. /** The "File", "Edit", "Run", "Option", "Window", and "Help" menus. */
  239. private JMenu filemenu, editmenu, runmenu, optmenu, windowmenu, windowmenu2, helpmenu;
  240. /** The toolbar. */
  241. private JToolBar toolbar;
  242. /** The various toolbar buttons. */
  243. private JButton runbutton, stopbutton, showbutton;
  244. /** The Splitpane. */
  245. private JSplitPane splitpane;
  246. /** The JLabel that displays the current line/column position, etc. */
  247. private JLabel status;
  248. /** Whether the editor has the focus, or the log window has the focus. */
  249. private boolean lastFocusIsOnEditor = true;
  250. /** The text editor. */
  251. private OurTabbedSyntaxWidget text;
  252. /** The "message panel" on the right. */
  253. private SwingLogPanelCustom log;
  254. /** The scrollpane containing the "message panel". */
  255. private JScrollPane logpane;
  256. /** The last "find" that the user issued. */
  257. private String lastFind = "";
  258. /** The last find is case-sensitive or not. */
  259. private boolean lastFindCaseSensitive = true;
  260. /** The last find is forward or not. */
  261. private boolean lastFindForward = true;
  262. /** The icon for a "checked" menu item. */
  263. private static final Icon iconYes = OurUtil.loadIcon("images/menu1.gif");
  264. /** The icon for an "unchecked" menu item. */
  265. private static final Icon iconNo = OurUtil.loadIcon("images/menu0.gif");
  266. /** The system-specific file separator (forward-slash on UNIX, back-slash on Windows, etc.) */
  267. private static final String fs = System.getProperty("file.separator");
  268. /** The darker background color (for the MessageLog window and the Toolbar and the Status Bar, etc.) */
  269. private static final Color background = new Color(0.9f, 0.9f, 0.9f);
  270. /** If subrunning==true: 0 means SAT solving; 1 means metamodel; 2 means enumeration. */
  271. private int subrunningTask = 0;
  272. /** The amount of memory (in MB) currently allocated for this.subprocess */
  273. private int subMemoryNow = 0;
  274. /** The amount of stack (in KB) currently allocated for this.subprocess */
  275. private int subStackNow = 0;
  276. /** The list of commands (this field will be cleared to null when the text buffer is edited). */
  277. private List<Command> commands = null;
  278. /** The latest executed command. */
  279. private int latestCommand = 0;
  280. /** The current choices of SAT solver. */
  281. private List<SatSolver> satChoices;
  282. /** The most recent Alloy version (as queried from alloy.mit.edu); -1 if alloy.mit.edu has not replied yet. */
  283. private int latestAlloyVersion = (-1);
  284. /** The most recent Alloy version name (as queried from alloy.mit.edu); "unknown" if alloy.mit.edu has not replied yet. */
  285. private String latestAlloyVersionName = "unknown";
  286. /** If it's not "", then it is the XML filename for the latest satisfying instance or the latest metamodel. */
  287. private String latestInstance = "";
  288. /** If it's not "", then it is the latest instance or metamodel during the most recent click of "Execute". */
  289. private String latestAutoInstance = "";
  290. /** If true, that means the event handlers should return a Runner encapsulating them, rather than perform the actual work. */
  291. private boolean wrap = false;
  292. //===================================================================================================//
  293. /** frame is visible. */
  294. public boolean isVisible=true;
  295. /** theme path. */
  296. public String themePath="";
  297. private boolean initialized=false;
  298. public boolean isInitialized() { return initialized; }
  299. public void setIsInitialized(boolean value) { initialized=value; }
  300. //====== helper methods =================================================//
  301. /** Inserts "filename" into the "recently opened file list". */
  302. private void addHistory(String filename) {
  303. String name0=Model0.get(), name1=Model1.get(), name2=Model2.get();
  304. if (name0.equals(filename)) return; else {Model0.set(filename); Model1.set(name0);}
  305. if (name1.equals(filename)) return; else Model2.set(name1);
  306. if (name2.equals(filename)) return; else Model3.set(name2);
  307. }
  308. /** Sets the flag "lastFocusIsOnEditor" to be true. */
  309. private Runner notifyFocusGained() {
  310. if (wrap) return wrapMe();
  311. lastFocusIsOnEditor=true;
  312. return null;
  313. }
  314. /** Sets the flag "lastFocusIsOnEditor" to be false. */
  315. void notifyFocusLost() { lastFocusIsOnEditor=false; }
  316. /** Updates the status bar at the bottom of the screen. */
  317. private Runner notifyChange() {
  318. if (wrap) return wrapMe();
  319. commands=null;
  320. if (text==null) return null; // If this was called prior to the "text" being fully initialized
  321. OurSyntaxWidget t = text.get();
  322. if (Util.onMac()) frame.getRootPane().putClientProperty("windowModified", Boolean.valueOf(t.modified()));
  323. if (t.isFile()) frame.setTitle(t.getFilename()); else frame.setTitle("Alloy Analyzer "+Version.version());
  324. toolbar.setBorder(new OurBorder(false, false, text.count()<=1, false));
  325. int c = t.getCaret();
  326. int y = t.getLineOfOffset(c)+1;
  327. int x = c - t.getLineStartOffset(y-1)+1;
  328. status.setText("<html>&nbsp; Line "+y+", Column "+x
  329. +(t.modified()?" <b style=\"color:#B43333;\">[modified]</b></html>":"</html>"));
  330. return null;
  331. }
  332. /** Helper method that returns a hopefully very short name for a file name. */
  333. public static String slightlyShorterFilename(String name) {
  334. if (name.toLowerCase(Locale.US).endsWith(".als")) {
  335. int i=name.lastIndexOf('/');
  336. if (i>=0) name=name.substring(i+1);
  337. i=name.lastIndexOf('\\');
  338. if (i>=0) name=name.substring(i+1);
  339. return name.substring(0, name.length()-4);
  340. } else if (name.toLowerCase(Locale.US).endsWith(".xml")) {
  341. int i=name.lastIndexOf('/');
  342. if (i>0) i=name.lastIndexOf('/', i-1);
  343. if (i>=0) name=name.substring(i+1);
  344. i=name.lastIndexOf('\\');
  345. if (i>0) i=name.lastIndexOf('\\', i-1);
  346. if (i>=0) name=name.substring(i+1);
  347. return name.substring(0, name.length()-4);
  348. }
  349. return name;
  350. }
  351. /** Copy the required files from the JAR into a temporary directory. */
  352. private void copyFromJAR() {
  353. // Compute the appropriate platform
  354. String os = System.getProperty("os.name").toLowerCase(Locale.US).replace(' ','-');
  355. if (os.startsWith("mac-")) os="mac"; else if (os.startsWith("windows-")) os="windows";
  356. String arch = System.getProperty("os.arch").toLowerCase(Locale.US).replace(' ','-');
  357. if (arch.equals("powerpc")) arch="ppc-"+os; else arch=arch.replaceAll("\\Ai[3456]86\\z","x86")+"-"+os;
  358. if (os.equals("mac")) arch="x86-mac"; // our pre-compiled binaries are all universal binaries
  359. // Find out the appropriate Alloy directory
  360. final String platformBinary = alloyHome() + fs + "binary";
  361. // Write a few test files
  362. try {
  363. (new File(platformBinary)).mkdirs();
  364. Util.writeAll(platformBinary + fs + "tmp.cnf", "p cnf 3 1\n1 0\n");
  365. } catch(Err er) {
  366. // The error will be caught later by the "berkmin" or "spear" test
  367. }
  368. // Copy the platform-dependent binaries
  369. Util.copy(true, false, platformBinary,
  370. arch+"/libminisat.so", arch+"/libminisatx1.so", arch+"/libminisat.jnilib",
  371. arch+"/libminisatprover.so", arch+"/libminisatproverx1.so", arch+"/libminisatprover.jnilib",
  372. arch+"/libzchaff.so", arch+"/libzchaffx1.so", arch+"/libzchaff.jnilib",
  373. arch+"/berkmin", arch+"/spear");
  374. Util.copy(false, false, platformBinary,
  375. arch+"/minisat.dll", arch+"/minisatprover.dll", arch+"/zchaff.dll",
  376. arch+"/berkmin.exe", arch+"/spear.exe");
  377. // Copy the model files
  378. Util.copy(false, true, alloyHome(),
  379. "models/book/appendixA/addressBook1.als", "models/book/appendixA/addressBook2.als", "models/book/appendixA/barbers.als",
  380. "models/book/appendixA/closure.als", "models/book/appendixA/distribution.als", "models/book/appendixA/phones.als",
  381. "models/book/appendixA/prison.als", "models/book/appendixA/properties.als", "models/book/appendixA/ring.als",
  382. "models/book/appendixA/spanning.als", "models/book/appendixA/tree.als", "models/book/appendixA/tube.als", "models/book/appendixA/undirected.als",
  383. "models/book/appendixE/hotel.thm", "models/book/appendixE/p300-hotel.als", "models/book/appendixE/p303-hotel.als", "models/book/appendixE/p306-hotel.als",
  384. "models/book/chapter2/addressBook1a.als", "models/book/chapter2/addressBook1b.als", "models/book/chapter2/addressBook1c.als",
  385. "models/book/chapter2/addressBook1d.als", "models/book/chapter2/addressBook1e.als", "models/book/chapter2/addressBook1f.als",
  386. "models/book/chapter2/addressBook1g.als", "models/book/chapter2/addressBook1h.als", "models/book/chapter2/addressBook2a.als",
  387. "models/book/chapter2/addressBook2b.als", "models/book/chapter2/addressBook2c.als", "models/book/chapter2/addressBook2d.als",
  388. "models/book/chapter2/addressBook2e.als", "models/book/chapter2/addressBook3a.als", "models/book/chapter2/addressBook3b.als",
  389. "models/book/chapter2/addressBook3c.als", "models/book/chapter2/addressBook3d.als", "models/book/chapter2/theme.thm",
  390. "models/book/chapter4/filesystem.als", "models/book/chapter4/grandpa1.als",
  391. "models/book/chapter4/grandpa2.als", "models/book/chapter4/grandpa3.als", "models/book/chapter4/lights.als",
  392. "models/book/chapter5/addressBook.als", "models/book/chapter5/lists.als", "models/book/chapter5/sets1.als", "models/book/chapter5/sets2.als",
  393. "models/book/chapter6/hotel.thm", "models/book/chapter6/hotel1.als", "models/book/chapter6/hotel2.als",
  394. "models/book/chapter6/hotel3.als", "models/book/chapter6/hotel4.als", "models/book/chapter6/mediaAssets.als",
  395. "models/book/chapter6/memory/abstractMemory.als", "models/book/chapter6/memory/cacheMemory.als",
  396. "models/book/chapter6/memory/checkCache.als", "models/book/chapter6/memory/checkFixedSize.als",
  397. "models/book/chapter6/memory/fixedSizeMemory.als", "models/book/chapter6/memory/fixedSizeMemory_H.als",
  398. "models/book/chapter6/ringElection.thm", "models/book/chapter6/ringElection1.als", "models/book/chapter6/ringElection2.als",
  399. "models/examples/algorithms/dijkstra.als", "models/examples/algorithms/dijkstra.thm",
  400. "models/examples/algorithms/messaging.als", "models/examples/algorithms/messaging.thm",
  401. "models/examples/algorithms/opt_spantree.als", "models/examples/algorithms/opt_spantree.thm",
  402. "models/examples/algorithms/peterson.als",
  403. "models/examples/algorithms/ringlead.als", "models/examples/algorithms/ringlead.thm",
  404. "models/examples/algorithms/s_ringlead.als",
  405. "models/examples/algorithms/stable_mutex_ring.als", "models/examples/algorithms/stable_mutex_ring.thm",
  406. "models/examples/algorithms/stable_orient_ring.als", "models/examples/algorithms/stable_orient_ring.thm",
  407. "models/examples/algorithms/stable_ringlead.als", "models/examples/algorithms/stable_ringlead.thm",
  408. "models/examples/case_studies/INSLabel.als", "models/examples/case_studies/chord.als",
  409. "models/examples/case_studies/chord2.als", "models/examples/case_studies/chordbugmodel.als",
  410. "models/examples/case_studies/com.als", "models/examples/case_studies/firewire.als", "models/examples/case_studies/firewire.thm",
  411. "models/examples/case_studies/ins.als", "models/examples/case_studies/iolus.als",
  412. "models/examples/case_studies/sync.als", "models/examples/case_studies/syncimpl.als",
  413. "models/examples/puzzles/farmer.als", "models/examples/puzzles/farmer.thm",
  414. "models/examples/puzzles/handshake.als", "models/examples/puzzles/handshake.thm",
  415. "models/examples/puzzles/hanoi.als", "models/examples/puzzles/hanoi.thm",
  416. "models/examples/systems/file_system.als", "models/examples/systems/file_system.thm",
  417. "models/examples/systems/javatypes_soundness.als",
  418. "models/examples/systems/lists.als", "models/examples/systems/lists.thm",
  419. "models/examples/systems/marksweepgc.als", "models/examples/systems/views.als",
  420. "models/examples/toys/birthday.als", "models/examples/toys/birthday.thm",
  421. "models/examples/toys/ceilingsAndFloors.als", "models/examples/toys/ceilingsAndFloors.thm",
  422. "models/examples/toys/genealogy.als", "models/examples/toys/genealogy.thm",
  423. "models/examples/toys/grandpa.als", "models/examples/toys/grandpa.thm",
  424. "models/examples/toys/javatypes.als", "models/examples/toys/life.als", "models/examples/toys/life.thm",
  425. "models/examples/toys/numbering.als", "models/examples/toys/railway.als", "models/examples/toys/railway.thm",
  426. "models/examples/toys/trivial.als",
  427. "models/examples/tutorial/farmer.als",
  428. "models/util/boolean.als", "models/util/graph.als", "models/util/integer.als", "models/util/natural.als",
  429. "models/util/ordering.als", "models/util/relation.als", "models/util/seqrel.als", "models/util/sequence.als",
  430. "models/util/sequniv.als", "models/util/ternary.als", "models/util/time.als"
  431. );
  432. // Record the locations
  433. System.setProperty("alloy.theme0", alloyHome() + fs + "models");
  434. System.setProperty("alloy.home", alloyHome());
  435. }
  436. /** Called when this window is resized. */
  437. public void componentResized(ComponentEvent e) {
  438. componentMoved(e);
  439. }
  440. /** Called when this window is moved. */
  441. public void componentMoved(ComponentEvent e) {
  442. AnalyzerWidth.set(frame.getWidth());
  443. AnalyzerHeight.set(frame.getHeight());
  444. AnalyzerX.set(frame.getX());
  445. AnalyzerY.set(frame.getY());
  446. }
  447. /** Called when this window is shown. */
  448. public void componentShown(ComponentEvent e) {}
  449. /** Called when this window is hidden. */
  450. public void componentHidden(ComponentEvent e) {}
  451. /** Wraps the calling method into a Runnable whose run() will call the calling method with (false) as the only argument. */
  452. private Runner wrapMe() {
  453. final String name;
  454. try { throw new Exception(); } catch(Exception ex) { name = ex.getStackTrace()[1].getMethodName(); }
  455. Method[] methods = getClass().getDeclaredMethods();
  456. Method m=null;
  457. for(int i=0; i<methods.length; i++) if (methods[i].getName().equals(name)) { m=methods[i]; break; }
  458. final Method method=m;
  459. return new Runner() {
  460. private static final long serialVersionUID = 0;
  461. public void run() {
  462. try {
  463. method.setAccessible(true);
  464. method.invoke(SimpleGUICustom.this, new Object[]{});
  465. } catch (Throwable ex) {
  466. ex = new IllegalArgumentException("Failed call to "+name+"()", ex);
  467. Thread.getDefaultUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), ex);
  468. }
  469. }
  470. public void run(Object arg) { run(); }
  471. };
  472. }
  473. /** Wraps the calling method into a Runnable whose run() will call the calling method with (false,argument) as the two arguments. */
  474. private Runner wrapMe(final Object argument) {
  475. final String name;
  476. try { throw new Exception(); } catch(Exception ex) { name = ex.getStackTrace()[1].getMethodName(); }
  477. Method[] methods = getClass().getDeclaredMethods();
  478. Method m=null;
  479. for(int i=0; i<methods.length; i++) if (methods[i].getName().equals(name)) { m=methods[i]; break; }
  480. final Method method=m;
  481. return new Runner() {
  482. private static final long serialVersionUID = 0;
  483. public void run(Object arg) {
  484. try {
  485. method.setAccessible(true);
  486. method.invoke(SimpleGUICustom.this, new Object[]{arg});
  487. } catch (Throwable ex) {
  488. ex = new IllegalArgumentException("Failed call to "+name+"("+arg+")", ex);
  489. Thread.getDefaultUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), ex);
  490. }
  491. }
  492. public void run() { run(argument); }
  493. };
  494. }
  495. /** This variable caches the result of alloyHome() function call. */
  496. private static String alloyHome = null;
  497. /** Find a temporary directory to store Alloy files; it's guaranteed to be a canonical absolute path. */
  498. private static synchronized String alloyHome() {
  499. if (alloyHome!=null) return alloyHome;
  500. String temp=System.getProperty("java.io.tmpdir");
  501. if (temp==null || temp.length()==0)
  502. OurDialog.fatal("Error. JVM need to specify a temporary directory using java.io.tmpdir property.");
  503. String username=System.getProperty("user.name");
  504. File tempfile=new File(temp+File.separatorChar+"alloy4tmp40-"+(username==null?"":username));
  505. tempfile.mkdirs();
  506. String ans=Util.canon(tempfile.getPath());
  507. if (!tempfile.isDirectory()) {
  508. OurDialog.fatal("Error. Cannot create the temporary directory "+ans);
  509. }
  510. if (!Util.onWindows()) {
  511. String[] args={"chmod", "700", ans};
  512. try {Runtime.getRuntime().exec(args).waitFor();}
  513. catch (Throwable ex) {} // We only intend to make a best effort.
  514. }
  515. return alloyHome=ans;
  516. }
  517. /** Create an empty temporary directory for use, designate it "deleteOnExit", then return it.
  518. * It is guaranteed to be a canonical absolute path. */
  519. private static String maketemp() {
  520. Random r=new Random(new Date().getTime());
  521. while(true) {
  522. int i=r.nextInt(1000000);
  523. String dest = alloyHome()+File.separatorChar+"tmp"+File.separatorChar+i;
  524. File f=new File(dest);
  525. if (f.mkdirs()) {
  526. f.deleteOnExit();
  527. return Util.canon(dest);
  528. }
  529. }
  530. }
  531. /** Return the number of bytes used by the Temporary Directory (or return -1 if the answer exceeds "long") */
  532. private static long computeTemporarySpaceUsed() {
  533. long ans = iterateTemp(null,false);
  534. if (ans<0) return -1; else return ans;
  535. }
  536. /** Delete every file in the Temporary Directory. */
  537. private static void clearTemporarySpace() {
  538. iterateTemp(null,true);
  539. // Also clear the temp dir from previous versions of Alloy4
  540. String temp=System.getProperty("java.io.tmpdir");
  541. if (temp==null || temp.length()==0) return;
  542. String username=System.getProperty("user.name");
  543. if (username==null) username="";
  544. for(int i=1; i<40; i++) iterateTemp(temp+File.separatorChar+"alloy4tmp"+i+"-"+username, true);
  545. }
  546. /** Helper method for performing either computeTemporarySpaceUsed() or clearTemporarySpace() */
  547. private static long iterateTemp(String filename, boolean delete) {
  548. long ans=0;
  549. if (filename==null) filename = alloyHome()+File.separatorChar+"tmp";
  550. File x = new File(filename);
  551. if (x.isDirectory()) {
  552. for(String subfile:x.list()) {
  553. long tmp=iterateTemp(filename+File.separatorChar+subfile, delete);
  554. if (ans>=0) ans=ans+tmp;
  555. }
  556. }
  557. else if (x.isFile()) {
  558. long tmp=x.length();
  559. if (ans>=0) ans=ans+tmp;
  560. }
  561. if (delete) x.delete();
  562. return ans;
  563. }
  564. //===============================================================================================================//
  565. /** This method refreshes the "file" menu. */
  566. private Runner doRefreshFile() {
  567. if (wrap) return wrapMe();
  568. try {
  569. wrap = true;
  570. filemenu.removeAll();
  571. menuItem(filemenu, "New", 'N', 'N', doNew());
  572. menuItem(filemenu, "Open...", 'O', 'O', doOpen());
  573. if (!Util.onMac())
  574. menuItem(filemenu, "Open Sample Models...", VK_ALT, 'O', doBuiltin());
  575. else
  576. menuItem(filemenu, "Open Sample Models...", doBuiltin());
  577. JMenu recentmenu;
  578. filemenu.add(recentmenu = new JMenu("Open Recent"));
  579. menuItem(filemenu, "Reload all", 'R', 'R', doReloadAll());
  580. menuItem(filemenu, "Save", 'S', 'S', doSave());
  581. if (Util.onMac())
  582. menuItem(filemenu, "Save As...", VK_SHIFT, 'S', doSaveAs());
  583. else
  584. menuItem(filemenu, "Save As...", 'A', doSaveAs());
  585. menuItem(filemenu, "Close", 'W', 'W', doClose());
  586. menuItem(filemenu, "Clear Temporary Directory", doClearTemp());
  587. menuItem(filemenu, "Quit", 'Q', (Util.onMac() ? -1 : 'Q'), doQuit());
  588. boolean found = false;
  589. for(Util.StringPref p: new Util.StringPref[]{ Model0, Model1, Model2, Model3 }) {
  590. String name = p.get();
  591. if (name.length()>0) { found = true; menuItem(recentmenu, name, doOpenFile(name)); }
  592. }
  593. recentmenu.addSeparator();
  594. menuItem(recentmenu, "Clear Menu", doClearRecent());
  595. recentmenu.setEnabled(found);
  596. } finally {
  597. wrap = false;
  598. }
  599. return null;
  600. }
  601. /** This method performs File->New. */
  602. public Runner doNew() {
  603. if (!wrap) { text.newtab(null); notifyChange(); doShow(); }
  604. return wrapMe();
  605. }
  606. /** This method performs File->Open. */
  607. public Runner doOpen() {
  608. if (wrap) return wrapMe();
  609. File file=OurDialog.askFile(true, null, ".als", ".als files");
  610. if (file!=null) {
  611. Util.setCurrentDirectory(file.getParentFile());
  612. doOpenFile(file.getPath());
  613. }
  614. return null;
  615. }
  616. /** This method performs File->OpenBuiltinModels. */
  617. public Runner doBuiltin() {
  618. if (wrap) return wrapMe();
  619. File file=OurDialog.askFile(true, alloyHome() + fs + "models", ".als", ".als files");
  620. if (file!=null) {
  621. doOpenFile(file.getPath());
  622. }
  623. return null;
  624. }
  625. /** This method performs File->ReloadAll. */
  626. public Runner doReloadAll() {
  627. if (!wrap) text.reloadAll();
  628. return wrapMe();
  629. }
  630. /** This method performs File->ClearRecentFiles. */
  631. public Runner doClearRecent() {
  632. if (!wrap) { Model0.set(""); Model1.set(""); Model2.set(""); Model3.set(""); }
  633. return wrapMe();
  634. }
  635. /** This method performs File->Save. */
  636. public Runner doSave() {
  637. if (!wrap) {
  638. String ans = text.save(false);
  639. if (ans==null) return null;
  640. notifyChange();
  641. addHistory(ans);
  642. log.clearError();
  643. }
  644. return wrapMe();
  645. }
  646. /** This method performs File->SaveAs. */
  647. public Runner doSaveAs() {
  648. if (!wrap) {
  649. String ans = text.save(true);
  650. if (ans==null) return null;
  651. notifyChange();
  652. addHistory(ans);
  653. log.clearError();
  654. }
  655. return wrapMe();
  656. }
  657. /** This method clears the temporary files and then reinitialize the temporary directory. */
  658. public Runner doClearTemp() {
  659. if (!wrap) {
  660. clearTemporarySpace();
  661. copyFromJAR();
  662. log.logBold("Temporary directory has been cleared.\n\n");
  663. log.logDivider();
  664. log.flush();
  665. }
  666. return wrapMe();
  667. }
  668. /** This method performs File->Close. */
  669. public Runner doClose() {
  670. if (!wrap) text.close();
  671. return wrapMe();
  672. }
  673. /** This method performs File->Quit. */
  674. public Runner doQuit() {
  675. if (!wrap) if (text.closeAll()) {
  676. try { WorkerEngineCustom.stop(); } finally { }
  677. }
  678. return wrapMe();
  679. }
  680. //===============================================================================================================//
  681. /** This method refreshes the "edit" menu. */
  682. private Runner doRefreshEdit() {
  683. if (wrap) return wrapMe();
  684. try {
  685. wrap = true;
  686. boolean canUndo = text.get().canUndo();
  687. boolean canRedo = text.get().canRedo();
  688. editmenu.removeAll();
  689. menuItem(editmenu, "Undo", 'Z', 'Z', doUndo(), canUndo);
  690. if (Util.onMac())
  691. menuItem(editmenu, "Redo", VK_SHIFT, 'Z', doRedo(), canRedo);
  692. else
  693. menuItem(editmenu, "Redo", 'Y', 'Y', doRedo(), canRedo);
  694. editmenu.addSeparator();
  695. menuItem(editmenu, "Cut", 'X', 'X', doCut());
  696. menuItem(editmenu, "Copy", 'C', 'C', doCopy());
  697. menuItem(editmenu, "Paste", 'V', 'V', doPaste());
  698. editmenu.addSeparator();
  699. menuItem(editmenu, "Go To..." , 'T', 'T', doGoto());
  700. menuItem(editmenu, "Previous File" , VK_PAGE_UP, VK_PAGE_UP, doGotoPrevFile(), text.count()>1);
  701. menuItem(editmenu, "Next File" , VK_PAGE_DOWN, VK_PAGE_DOWN, doGotoNextFile(), text.count()>1);
  702. editmenu.addSeparator();
  703. menuItem(editmenu, "Find...", 'F', 'F', doFind());
  704. menuItem(editmenu, "Find Next", 'G', 'G', doFindNext());
  705. } finally {
  706. wrap = false;
  707. }
  708. return null;
  709. }
  710. /** This method performs Edit->Undo. */
  711. public Runner doUndo() {
  712. if (!wrap) text.get().undo();
  713. return wrapMe();
  714. }
  715. /** This method performs Edit->Redo. */
  716. public Runner doRedo() {
  717. if (!wrap) text.get().redo();
  718. return wrapMe();
  719. }
  720. /** This method performs Edit->Copy. */
  721. public Runner doCopy() {
  722. if (!wrap) { if (lastFocusIsOnEditor) text.get().copy(); else log.copy(); }
  723. return wrapMe();
  724. }
  725. /** This method performs Edit->Cut. */
  726. public Runner doCut() {
  727. if (!wrap && lastFocusIsOnEditor) text.get().cut();
  728. return wrapMe();
  729. }
  730. /** This method performs Edit->Paste. */
  731. public Runner doPaste() {
  732. if (!wrap && lastFocusIsOnEditor) text.get().paste();
  733. return wrapMe();
  734. }
  735. /** This method performs Edit->Find. */
  736. public Runner doFind() {
  737. if (wrap) return wrapMe();
  738. JTextField x = OurUtil.textfield(lastFind,30);
  739. x.selectAll();
  740. JCheckBox c = new JCheckBox("Case Sensitive?",lastFindCaseSensitive);
  741. c.setMnemonic('c');
  742. JCheckBox b = new JCheckBox("Search Backward?",!lastFindForward);
  743. b.setMnemonic('b');
  744. if (!OurDialog.getInput("Find", "Text:", x, " ", c, b)) return null;
  745. if (x.getText().length() == 0) return null;
  746. lastFind = x.getText();
  747. lastFindCaseSensitive = c.getModel().isSelected();
  748. lastFindForward = !b.getModel().isSelected();
  749. doFindNext();
  750. return null;
  751. }
  752. /** This method performs Edit->FindNext. */
  753. public Runner doFindNext() {
  754. if (wrap) return wrapMe();
  755. if (lastFind.length()==0) return null;
  756. OurSyntaxWidget t = text.get();
  757. String all = t.getText();
  758. int i = Util.indexOf(all, lastFind, t.getCaret()+(lastFindForward?0:-1),lastFindForward,lastFindCaseSensitive);
  759. if (i<0) {
  760. i=Util.indexOf(all, lastFind, lastFindForward?0:(all.length()-1), lastFindForward, lastFindCaseSensitive);
  761. if (i<0) { log.logRed("The specified search string cannot be found."); return null; }
  762. log.logRed("Search wrapped.");
  763. } else {
  764. log.clearError();
  765. }
  766. if (lastFindForward) t.moveCaret(i, i+lastFind.length()); else t.moveCaret(i+lastFind.length(), i);
  767. t.requestFocusInWindow();
  768. return null;
  769. }
  770. /** This method performs Edit->Goto. */
  771. public Runner doGoto() {
  772. if (wrap) return wrapMe();
  773. JTextField y = OurUtil.textfield("", 10);
  774. JTextField x = OurUtil.textfield("", 10);
  775. if (!OurDialog.getInput("Go To", "Line Number:", y, "Column Number (optional):", x)) return null;
  776. try {
  777. OurSyntaxWidget t = text.get();
  778. int xx = 1, yy = Integer.parseInt(y.getText()), lineCount = t.getLineCount();
  779. if (yy<1) return null;
  780. if (yy>lineCount) {log.logRed("This file only has "+lineCount+" line(s)."); return null;}
  781. if (x.getText().length()!=0) xx=Integer.parseInt(x.getText());
  782. if (xx<1) {log.logRed("If the column number is specified, it must be 1 or greater."); return null;}
  783. int caret = t.getLineStartOffset(yy-1);
  784. int len = (yy==lineCount ? t.getText().length()+1 : t.getLineStartOffset(yy)) - caret;
  785. if (xx>len) xx=len;
  786. if (xx<1) xx=1;
  787. t.moveCaret(caret+xx-1, caret+xx-1);
  788. t.requestFocusInWindow();
  789. } catch(NumberFormatException ex) {
  790. log.logRed("The number must be 1 or greater.");
  791. } catch(Throwable ex) {
  792. // This error is not important
  793. }
  794. return null;
  795. }
  796. /** This method performs Edit->GotoPrevFile. */
  797. public Runner doGotoPrevFile() {
  798. if (wrap) return wrapMe(); else {text.prev(); return null;}
  799. }
  800. /** This method performs Edit->GotoNextFile. */
  801. public Runner doGotoNextFile() {
  802. if (wrap) return wrapMe(); else {text.next(); return null;}
  803. }
  804. //===============================================================================================================//
  805. /** This method refreshes the "run" menu. */
  806. public Runner doRefreshRun() {
  807. if (wrap) return wrapMe();
  808. KeyStroke ac = KeyStroke.getKeyStroke(VK_E, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
  809. try {
  810. wrap = true;
  811. runmenu.removeAll();
  812. menuItem(runmenu, "Execute Latest Command", 'E', 'E', doExecuteLatest());
  813. runmenu.add(new JSeparator());
  814. menuItem(runmenu, "Show Latest Instance", 'L', 'L', doShowLatest(), latestInstance.length()>0);
  815. menuItem(runmenu, "Show Metamodel", 'M', 'M', doShowMetaModel());
  816. if (Version.experimental) menuItem(runmenu, "Show Parse Tree", 'P', doShowParseTree());
  817. menuItem(runmenu, "Open Evaluator", 'V', doLoadEvaluator());
  818. } finally {
  819. wrap = false;
  820. }
  821. List<Command> cp = commands;
  822. if (cp==null) {
  823. try {
  824. cp=CompUtil.parseOneModule_fromString(text.get().getText());
  825. }
  826. catch(Err e) {
  827. commands = null;
  828. runmenu.getItem(0).setEnabled(false);
  829. runmenu.getItem(3).setEnabled(false);
  830. text.shade(new Pos(text.get().getFilename(), e.pos.x, e.pos.y, e.pos.x2, e.pos.y2));
  831. if ("yes".equals(System.getProperty("debug")) && Verbosity.get()==Verbosity.FULLDEBUG)
  832. log.logRed("Fatal Exception!" + e.dump() + "\n\n");
  833. else
  834. log.logRed(e.toString()+"\n\n");
  835. return null;
  836. }
  837. catch(Throwable e) {
  838. commands = null;
  839. runmenu.getItem(0).setEnabled(false);
  840. runmenu.getItem(3).setEnabled(false);
  841. log.logRed("Cannot parse the model.\n"+e.toString()+"\n\n");
  842. return null;
  843. }
  844. commands=cp;
  845. }
  846. text.clearShade();
  847. log.clearError(); // To clear any residual error message
  848. if (cp==null) { runmenu.getItem(0).setEnabled(false); runmenu.getItem(3).setEnabled(false); return null; }
  849. if (cp.size()==0) { runmenu.getItem(0).setEnabled(false); return null; }
  850. if (latestCommand>=cp.size()) latestCommand=cp.size()-1;
  851. runmenu.remove(0);
  852. try {
  853. wrap = true;
  854. for(int i=0; i<cp.size(); i++) {
  855. JMenuItem y = new JMenuItem(cp.get(i).toString(), null);
  856. y.addActionListener(doRun(i));
  857. if (i==latestCommand) { y.setMnemonic(VK_E); y.setAccelerator(ac); }
  858. runmenu.add(y,i);
  859. }
  860. if (cp.size()>=2) {
  861. JMenuItem y = new JMenuItem("Execute All", null);
  862. y.setMnemonic(VK_A);
  863. y.addActionListener(doRun(-1));
  864. runmenu.add(y,0);
  865. runmenu.add(new JSeparator(),1);
  866. }
  867. } finally {
  868. wrap = false;
  869. }
  870. return null;
  871. }
  872. /** This method executes a particular RUN or CHECK command. */
  873. public Runner doRun(Integer commandIndex) {
  874. if (wrap) return wrapMe(commandIndex);
  875. final int index = commandIndex;
  876. if (WorkerEngineCustom.isBusy()) return null;
  877. if (index==(-2)) subrunningTask=1; else subrunningTask=0;
  878. latestAutoInstance="";
  879. if (index>=0) latestCommand=index;
  880. if (index==-1 && commands!=null) {
  881. latestCommand=commands.size()-1;
  882. if (latestCommand<0) latestCommand=0;
  883. }
  884. // To update the accelerator to point to the command actually chosen
  885. doRefreshRun();
  886. OurUtil.enableAll(runmenu);
  887. if (commands==null) return null;
  888. if (commands.size()==0 && index!=-2 && index!=-3) { log.logRed("There are no commands to execute.\n\n"); return null; }
  889. int i=index;
  890. if (i>=commands.size()) i=commands.size()-1;
  891. SimpleCallback1 cb = new SimpleCallback1(this, null, log, Verbosity.get().ordinal(), latestAlloyVersionName, latestAlloyVersion);
  892. SimpleTask1 task = new SimpleTask1();
  893. A4Options opt = new A4Options();
  894. opt.tempDirectory = alloyHome() + fs + "tmp";
  895. opt.solverDirectory = alloyHome() + fs + "binary";
  896. opt.recordKodkod = RecordKodkod.get();
  897. opt.noOverflow = NoOverflow.get();
  898. opt.unrolls = Version.experimental ? Unrolls.get() : (-1);
  899. opt.skolemDepth = SkolemDepth.get();
  900. opt.coreMinimization = CoreMinimization.get();
  901. opt.coreGranularity = CoreGranularity.get();
  902. opt.originalFilename = Util.canon(text.get().getFilename());
  903. opt.solver = SatSolver.get();
  904. task.bundleIndex = i;
  905. task.bundleWarningNonFatal = WarningNonfatal.get();
  906. task.map = text.takeSnapshot();
  907. task.options = opt.dup();
  908. task.resolutionMode = (Version.experimental && ImplicitThis.get()) ? 2 : 1;
  909. task.tempdir = maketemp();
  910. try {
  911. runmenu.setEnabled(false);
  912. runbutton.setVisible(false);
  913. showbutton.setEnabled(false);
  914. stopbutton.setVisible(true);
  915. int newmem = SubMemory.get(), newstack = SubStack.get();
  916. if (newmem != subMemoryNow || newstack != subStackNow) WorkerEngineCustom.stop();
  917. if ("yes".equals(System.getProperty("debug")) && Verbosity.get()==Verbosity.FULLDEBUG)
  918. WorkerEngineCustom.runLocally(task, cb);
  919. else
  920. WorkerEngineCustom.run(task, newmem, newstack, alloyHome() + fs + "binary", "", cb);
  921. subMemoryNow = newmem;
  922. subStackNow = newstack;
  923. } catch(Throwable ex) {
  924. WorkerEngineCustom.stop();
  925. log.logBold("Fatal Error: Solver failed due to unknown reason.\n" +
  926. "One possible cause is that, in the Options menu, your specified\n" +
  927. "memory size is larger than the amount allowed by your OS.\n" +
  928. "Also, please make sure \"java\" is in your program path.\n");
  929. log.logDivider();
  930. log.flush();
  931. doStop(2);
  932. }
  933. // load the custom theme...
  934. if ((!themePath.isEmpty()) && (themePath != null)) viz.loadThemeFile(themePath);
  935. return null;
  936. }
  937. /** This method stops the current run or check (how==0 means DONE, how==1 means FAIL, how==2 means STOP). */
  938. Runner doStop(Integer how) {
  939. if (wrap) return wrapMe(how);
  940. int h = how;
  941. if (h!=0) {
  942. if (h==2 && WorkerEngineCustom.isBusy()) { WorkerEngineCustom.stop(); log.logBold("\nSolving Stopped.\n"); log.logDivider(); }
  943. WorkerEngineCustom.stop();
  944. }
  945. runmenu.setEnabled(true);
  946. runbutton.setVisible(true);
  947. showbutton.setEnabled(true);
  948. stopbutton.setVisible(false);
  949. if (latestAutoInstance.length()>0) {
  950. String f=latestAutoInstance;
  951. latestAutoInstance="";
  952. if (subrunningTask==2) viz.loadXML(f, true); else if (AutoVisualize.get() || subrunningTask==1) doVisualize("XML: "+f);
  953. }
  954. return null;
  955. }
  956. /** This method executes the latest command. */
  957. public Runner doExecuteLatest() {
  958. if (wrap) return wrapMe();
  959. doRefreshRun();
  960. OurUtil.enableAll(runmenu);
  961. if (commands==null) return null;
  962. int n=commands.size();
  963. if (n<=0) { log.logRed("There are no commands to execute.\n\n"); return null; }
  964. if (latestCommand>=n) latestCommand=n-1;
  965. if (latestCommand<0) latestCommand=0;
  966. return doRun(latestCommand);
  967. }
  968. /** This method displays the parse tree. */
  969. public Runner doShowParseTree() {
  970. if (wrap) return wrapMe();
  971. doRefreshRun();
  972. OurUtil.enableAll(runmenu);
  973. if (commands!=null) {
  974. Module world = null;
  975. try {
  976. int resolutionMode = (Version.experimental && ImplicitThis.get()) ? 2 : 1;
  977. A4Options opt = new A4Options();
  978. opt.tempDirectory = alloyHome() + fs + "tmp";
  979. opt.solverDirectory = alloyHome() + fs + "binary";
  980. opt.originalFilename = Util.canon(text.get().getFilename());
  981. world = CompUtil.parseEverything_fromFile(A4Reporter.NOP, text.takeSnapshot(), opt.originalFilename, resolutionMode);
  982. } catch(Err er) {
  983. text.shade(er.pos);
  984. log.logRed(er.toString()+"\n\n");
  985. return null;
  986. }
  987. world.showAsTree(this);
  988. }
  989. return null;
  990. }
  991. /** This method displays the meta model. */
  992. private Runner doShowMetaModel() {
  993. if (wrap) return wrapMe();
  994. doRefreshRun();
  995. OurUtil.enableAll(runmenu);
  996. if (commands!=null) doRun(-2);
  997. return null;
  998. }
  999. /** This method displays the latest instance. */
  1000. private Runner doShowLatest() {
  1001. if (wrap) return wrapMe();
  1002. if (latestInstance.length()==0)
  1003. log.logRed("No previous instances are available for viewing.\n\n");
  1004. else
  1005. doVisualize("XML: "+latestInstance);
  1006. return null;
  1007. }
  1008. /** This method happens when the user tries to load the evaluator from the main GUI. */
  1009. private Runner doLoadEvaluator() {
  1010. if (wrap) return wrapMe();
  1011. log.logRed("Note: the evaluator is now in the visualizer.\n"
  1012. +"Just click the \"Evaluator\" toolbar button\n"
  1013. +"when an instance is shown in the visualizer.\n");
  1014. log.flush();
  1015. return null;
  1016. }
  1017. //===============================================================================================================//
  1018. /** This method refreshes the "Window" menu for either the SimpleGUI window (isViz==false) or the VizGUI window (isViz==true). */
  1019. private Runner doRefreshWindow(Boolean isViz) {
  1020. if (wrap) return wrapMe(isViz);
  1021. try {
  1022. wrap = true;
  1023. JMenu w = (isViz ? windowmenu2 : windowmenu);
  1024. w.removeAll();
  1025. if (isViz) {
  1026. viz.addMinMaxActions(w);
  1027. } else {
  1028. menuItem(w, "Minimize", 'M', doMinimize(), iconNo);
  1029. menuItem(w, "Zoom", doZoom(), iconNo);
  1030. }
  1031. w.addSeparator();
  1032. int i = 0;
  1033. for(String f: text.getFilenames()) {
  1034. JMenuItem it = new JMenuItem("Model: "+slightlyShorterFilename(f)+(text.modified(i) ? " *" : ""), null);
  1035. it.setIcon((f.equals(text.get().getFilename()) && !isViz) ? iconYes : iconNo);
  1036. it.addActionListener(f.equals(text.get().getFilename()) ? doShow() : doOpenFile(f));
  1037. w.add(it);
  1038. i++;
  1039. }
  1040. if (viz!=null) for(String f:viz.getInstances()) {
  1041. JMenuItem it = new JMenuItem("Instance: "+viz.getInstanceTitle(f), null);
  1042. it.setIcon((isViz && f.equals(viz.getXMLfilename())) ? iconYes : iconNo);
  1043. it.addActionListener(doVisualize("XML: "+f));
  1044. w.add(it);
  1045. }
  1046. } finally {
  1047. wrap = false;
  1048. }
  1049. return null;
  1050. }
  1051. /** This method minimizes the window. */
  1052. private Runner doMinimize() {
  1053. if (wrap) return wrapMe(); else {OurUtil.minimize(frame); return null;}
  1054. }
  1055. /** This method alternatingly maximizes or restores the window. */
  1056. private Runner doZoom() {
  1057. if (wrap) return wrapMe(); else {OurUtil.zoom(frame); return null;}
  1058. }
  1059. /** This method bring this window to the foreground. */
  1060. public Runner doShow() {
  1061. if (isVisible)
  1062. {
  1063. if (wrap) return wrapMe();
  1064. OurUtil.show(frame);
  1065. if(text.get()!=null) text.get().requestFocusInWindow();
  1066. }
  1067. return null;
  1068. }
  1069. //===============================================================================================================//
  1070. /** This method refreshes the "Option" menu. */
  1071. private Runner doRefreshOption() {
  1072. if (wrap) return wrapMe();
  1073. try {
  1074. wrap = true;
  1075. optmenu.removeAll();
  1076. menuItem(optmenu, "Welcome Message at Start Up: "+(Welcome.get() < welcomeLevel ? "Yes" : "No"), doOptWelcome());
  1077. //
  1078. final SatSolver now = SatSolver.get();
  1079. final JMenu sat = new JMenu("SAT Solver: "+now);
  1080. for(SatSolver sc:satChoices) { menuItem(sat, ""+sc, doOptSolver(sc), sc==now?iconYes:iconNo); }
  1081. optmenu.add(sat);
  1082. //
  1083. menuItem(optmenu, "Warnings are Fatal: "+(WarningNonfatal.get()?"No":"Yes"), doOptWarning());
  1084. //
  1085. final int mem = SubMemory.get();
  1086. final JMenu subMemoryMenu = new JMenu("Maximum Memory to Use: " + mem + "M");
  1087. for(int n: allowedMemorySizes) {
  1088. menuItem(subMemoryMenu, ""+n+"M", doOptMemory(n), n==mem?iconYes:iconNo);
  1089. }
  1090. optmenu.add(subMemoryMenu);
  1091. //
  1092. final int stack = SubStack.get();
  1093. final JMenu subStackMenu = new JMenu("Maximum Stack to Use: " + stack + "k");
  1094. boolean debug = "yes".equals(System.getProperty("debug"));
  1095. for(int n: new int[]{16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536}) {
  1096. if (debug || n>=1024) menuItem(subStackMenu, ""+n+"k", doOptStack(n), n==stack?iconYes:iconNo);
  1097. }
  1098. optmenu.add(subStackMenu);
  1099. //
  1100. final Verbosity vnow = Verbosity.get();
  1101. final JMenu verb = new JMenu("Message Verbosity: "+vnow);
  1102. for(Verbosity vb: Verbosity.values()) { menuItem(verb, ""+vb, doOptVerbosity(vb), vb==vnow?iconYes:iconNo); }
  1103. optmenu.add(verb);
  1104. //
  1105. menuItem(optmenu, "Syntax Highlighting: "+(SyntaxDisabled.get()?"No":"Yes"), doOptSyntaxHighlighting());
  1106. //
  1107. final int fontSize = FontSize.get();
  1108. final JMenu size = new JMenu("Font Size: "+fontSize);
  1109. for(int n: new Integer[]{9,10,11,12,14,16,18,20,22,24,26,28,32,36,40,44,48,54,60,66,72}) {
  1110. menuItem(size, ""+n, doOptFontsize(n), n==fontSize?iconYes:iconNo);
  1111. }
  1112. optmenu.add(size);
  1113. //
  1114. menuItem(optmenu, "Font: "+FontName.get()+"...", doOptFontname());
  1115. //
  1116. if (Util.onMac() || Util.onWindows()) menuItem(optmenu, "Use anti-aliasing: Yes", false);
  1117. else menuItem(optmenu, "Use anti-aliasing: "+(AntiAlias.get()?"Yes":"No"), doOptAntiAlias());
  1118. //
  1119. final int tabSize = TabSize.get();
  1120. final JMenu tabSizeMenu = new JMenu("Tab Size: "+tabSize);
  1121. for(int n=1; n<=12; n++) { menuItem(tabSizeMenu, ""+n, doOptTabsize(n), n==tabSize?iconYes:iconNo); }
  1122. optmenu.add(tabSizeMenu);
  1123. //
  1124. final int skDepth = SkolemDepth.get();
  1125. final JMenu skDepthMenu = new JMenu("Skolem Depth: "+skDepth);
  1126. for(int n=0; n<=4; n++) { menuItem(skDepthMenu, ""+n, doOptSkolemDepth(n), n==skDepth?iconYes:iconNo); }
  1127. optmenu.add(skDepthMenu);
  1128. //
  1129. if (Version.experimental) {
  1130. final int unrolls = Unrolls.get();
  1131. final JMenu unrollsMenu = new JMenu("Recursion Depth: "+(unrolls<0 ? "Disabled" : (""+unrolls)));
  1132. for(int n=(-1); n<=3; n++) { menuItem(unrollsMenu, (n<0 ? "Disabled" : (""+n)), doOptUnrolls(n), n==unrolls?iconYes:iconNo); }
  1133. optmenu.add(unrollsMenu);
  1134. }
  1135. //
  1136. final int min = CoreMinimization.get();
  1137. final String[] minLabelLong=new String[]{"Slow (guarantees local minimum)", "Medium", "Fast (initial unsat core)"};
  1138. final String[] minLabelShort=new String[]{"Slow", "Medium", "Fast"};
  1139. final JMenu cmMenu = new JMenu("Unsat Core Minimization Strategy: "+minLabelShort[min]);
  1140. for(int n=0; n<=2; n++) { menuItem(cmMenu, minLabelLong[n], doOptCore(n), n==min?iconYes:iconNo); }
  1141. if (now!=SatSolver.MiniSatProverJNI) cmMenu.setEnabled(false);
  1142. optmenu.add(cmMenu);
  1143. //
  1144. final int gran = CoreGranularity.get();
  1145. final String[] granLabelLong=new String[]{"Top-level conjuncts only", "Flatten the formula once at the beginning", "Flatten the formula at the beginning and after skolemizing", "In addition to flattening the formula twice, expand the quantifiers"};
  1146. final String[] granLabelShort=new String[]{"Top-level", "Flatten once", "Flatten twice", "Expand quantifiers"};
  1147. final JMenu cgMenu = new JMenu("Core Granularity: "+granLabelShort[gran]);
  1148. for(int n=0; n<granLabelLong.length; n++) { menuItem(cgMenu, granLabelLong[n], doCoreGran(n), n==gran?iconYes:iconNo); }
  1149. if (now!=SatSolver.MiniSatProverJNI) cgMenu.setEnabled(false);
  1150. optmenu.add(cgMenu);
  1151. //
  1152. menuItem(optmenu, "Visualize Automatically: "+(AutoVisualize.get()?"Yes":"No"), doOptAutoVisualize());
  1153. menuItem(optmenu, "Record the Kodkod Input/Output: "+(RecordKodkod.get()?"Yes":"No"), doOptRecordKodkod());
  1154. if (Version.experimental) menuItem(optmenu, "Enable \"implicit this\" name resolution: "+(ImplicitThis.get()?"Yes":"No"), doOptImplicitThis());
  1155. if (Version.experimental) menuItem(optmenu, "Forbid Overflow: "+(NoOverflow.get()?"Yes":"No"), doOptNoOverflow());
  1156. } finally {
  1157. wrap = false;
  1158. }
  1159. return null;
  1160. }
  1161. /** This method toggles the "show welcome message at startup" checkbox. */
  1162. private Runner doOptWelcome() {
  1163. if (!wrap) Welcome.set(Welcome.get() < welcomeLevel ? welcomeLevel : 0);
  1164. return wrapMe();
  1165. }
  1166. /** This method toggles the "warning is fatal" checkbox. */
  1167. private Runner doOptWarning() {
  1168. if (!wrap) WarningNonfatal.set(!WarningNonfatal.get());
  1169. return wrapMe();
  1170. }
  1171. /** This method changes the SAT solver to the given solver. */
  1172. private Runner doOptSolver(SatSolver solver) {
  1173. if (!wrap) solver.set();
  1174. return wrapMe(solver);
  1175. }
  1176. /** This method changes the amount of memory to use. */
  1177. private Runner doOptMemory(Integer size) {
  1178. if (!wrap) SubMemory.set(size);
  1179. return wrapMe(size);
  1180. }
  1181. /** This method changes the amount of stack to use. */
  1182. private Runner doOptStack(Integer size) {
  1183. if (!wrap) SubStack.set(size);
  1184. return wrapMe(size);
  1185. }
  1186. /** This method changes the message verbosity. */
  1187. private Runner doOptVerbosity(Verbosity verbosity) {
  1188. if (!wrap) verbosity.set();
  1189. return wrapMe(verbosity);
  1190. }
  1191. /** This method changes the font name. */
  1192. private Runner doOptFontname() {
  1193. if (wrap) return wrapMe();
  1194. int size=FontSize.get();
  1195. String f = OurDialog.askFont();
  1196. if (f.length()>0) {
  1197. FontName.set(f);
  1198. text.setFont(f, size, TabSize.get());
  1199. status.setFont(new Font(f, Font.PLAIN, size));
  1200. log.setFontName(f);
  1201. }
  1202. return null;
  1203. }
  1204. /** This method changes the font size. */
  1205. private Runner doOptFontsize(Integer size) {
  1206. if (wrap) return wrapMe(size);
  1207. int n=size;
  1208. FontSize.set(n);
  1209. String f = FontName.get();
  1210. text.setFont(f, n, TabSize.get());
  1211. status.setFont(new Font(f, Font.PLAIN, n));
  1212. log.setFontSize(n);
  1213. viz.doSetFontSize(n);
  1214. return null;
  1215. }
  1216. /** This method changes the tab size. */
  1217. private Runner doOptTabsize(Integer size) {
  1218. if (!wrap) { TabSize.set(size.intValue()); text.setFont(FontName.get(), FontSize.get(), size.intValue()); }
  1219. return wrapMe(size);
  1220. }
  1221. /** This method changes the number of unrolls. */
  1222. private Runner doOptUnrolls(Integer num) {
  1223. if (!wrap) Unrolls.set(num.intValue());
  1224. return wrapMe(num);
  1225. }
  1226. /** This method changes the skolem depth. */
  1227. private Runner doOptSkolemDepth(Integer size) {
  1228. if (!wrap) SkolemDepth.set(size.intValue());
  1229. return wrapMe(size);
  1230. }
  1231. /** This method changes the speed of unsat core minimization (larger integer means faster but less optimal). */
  1232. private Runner doOptCore(Integer speed) {
  1233. if (!wrap) CoreMinimization.set(speed.intValue());
  1234. return wrapMe(speed);
  1235. }
  1236. /** This method changes the granularity of the unsat core (larger integer means more granular). */
  1237. private Runner doCoreGran(Integer gran) {
  1238. if (!wrap) CoreGranularity.set(gran.intValue());
  1239. return wrapMe(gran);
  1240. }
  1241. /** This method toggles the "antialias" checkbox. */
  1242. private Runner doOptAntiAlias() {
  1243. if (!wrap) { boolean newValue = !AntiAlias.get(); AntiAlias.set(newValue); OurAntiAlias.enableAntiAlias(newValue); }
  1244. return wrapMe();
  1245. }
  1246. /** This method toggles the "visualize automatically" checkbox. */
  1247. private Runner doOptAutoVisualize() {
  1248. if (!wrap) AutoVisualize.set(!AutoVisualize.get());
  1249. return wrapMe();
  1250. }
  1251. /** This method toggles the "record Kodkod input/output" checkbox. */
  1252. private Runner doOptRecordKodkod() {
  1253. if (!wrap) RecordKodkod.set(!RecordKodkod.get());
  1254. return wrapMe();
  1255. }
  1256. /** This method toggles the "enable new `implicit this' name resolution" checkbox. */
  1257. private Runner doOptImplicitThis() {
  1258. if (!wrap) ImplicitThis.set(!ImplicitThis.get());
  1259. return wrapMe();
  1260. }
  1261. private Runner doOptNoOverflow() {
  1262. if (!wrap) NoOverflow.set(!NoOverflow.get());
  1263. return wrapMe();
  1264. }
  1265. /** This method toggles the "syntax highlighting" checkbox. */
  1266. private Runner doOptSyntaxHighlighting() {
  1267. if (!wrap) {
  1268. boolean flag = SyntaxDisabled.get();
  1269. text.enableSyntax(flag);
  1270. SyntaxDisabled.set(!flag);
  1271. }
  1272. return wrapMe();
  1273. }
  1274. //===============================================================================================================//
  1275. /** This method displays the about box. */
  1276. private Runner doAbout() {
  1277. if (wrap) return wrapMe();
  1278. OurDialog.showmsg("About Alloy Analyzer " + Version.version(),
  1279. OurUtil.loadIcon("images/logo.gif"),
  1280. "Alloy Analyzer " + Version.version(),
  1281. "Build date: " + Version.buildDate(),
  1282. " ",
  1283. "Lead developer: Felix Chang",
  1284. "Engine developer: Emina Torlak",
  1285. "Graphic design: Julie Pelaez",
  1286. "Project lead: Daniel Jackson",
  1287. " ",
  1288. "Please post comments and questions to the Alloy Community Forum at http://alloy.mit.edu/",
  1289. " ",
  1290. "Thanks to: Ilya Shlyakhter, Manu Sridharan, Derek Rayside, Jonathan Edwards, Gregory Dennis,",
  1291. "Robert Seater, Edmond Lau, Vincent Yeung, Sam Daitch, Andrew Yip, Jongmin Baek, Ning Song,",
  1292. "Arturo Arizpe, Li-kuo (Brian) Lin, Joseph Cohen, Jesse Pavel, Ian Schechter, and Uriel Schafer."
  1293. );
  1294. return null;
  1295. }
  1296. /** This method displays the help html. */
  1297. private Runner doHelp() {
  1298. if (wrap) return wrapMe();
  1299. try {
  1300. int w=OurUtil.getScreenWidth(), h=OurUtil.getScreenHeight();
  1301. final JFrame frame = new JFrame();
  1302. final JEditorPane html1 = new JEditorPane("text/html", "");
  1303. final JEditorPane html2 = new JEditorPane("text/html", "");
  1304. final HTMLDocument doc1 = (HTMLDocument) (html1.getDocument()); doc1.setAsynchronousLoadPriority(-1);
  1305. final HTMLDocument doc2 = (HTMLDocument) (html2.getDocument()); doc2.setAsynchronousLoadPriority(-1);
  1306. html1.setPage(this.getClass().getResource("/help/Nav.html"));
  1307. html2.setPage(this.getClass().getResource("/help/index.html"));
  1308. HyperlinkListener hl=new HyperlinkListener() {
  1309. public final void hyperlinkUpdate(HyperlinkEvent e) {
  1310. try {
  1311. if (e.getEventType()!=HyperlinkEvent.EventType.ACTIVATED) return;
  1312. if (e.getURL().getPath().endsWith("quit.htm")) { frame.dispose(); return; }
  1313. HTMLDocument doc = (HTMLDocument) (html2.getDocument());
  1314. doc.setAsynchronousLoadPriority(-1); // So that we can catch any exception that may occur
  1315. html2.setPage(e.getURL());
  1316. html2.requestFocusInWindow();
  1317. } catch(Throwable ex) { }
  1318. }
  1319. };
  1320. html1.setEditable(false); html1.setBorder(new EmptyBorder(3,3,3,3)); html1.addHyperlinkListener(hl);
  1321. html2.setEditable(false); html2.setBorder(new EmptyBorder(3,3,3,3)); html2.addHyperlinkListener(hl);
  1322. JScrollPane scroll1 = OurUtil.scrollpane(html1);
  1323. JScrollPane scroll2 = OurUtil.scrollpane(html2);
  1324. JSplitPane split = OurUtil.splitpane(JSplitPane.HORIZONTAL_SPLIT, scroll1, scroll2, 150);
  1325. split.setResizeWeight(0d);
  1326. frame.setTitle("Alloy Analyzer Online Guide");
  1327. frame.getContentPane().setLayout(new BorderLayout());
  1328. frame.getContentPane().add(split, BorderLayout.CENTER);
  1329. frame.pack();
  1330. frame.setSize(w-w/10, h-h/10);
  1331. frame.setLocation(w/20, h/20);
  1332. frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
  1333. frame.setVisible(true);
  1334. html2.requestFocusInWindow();
  1335. } catch(Throwable ex) { return null; }
  1336. return null;
  1337. }
  1338. /** This method displays the license box. */
  1339. private Runner doLicense() {
  1340. if (wrap) return wrapMe();
  1341. final String JAR = Util.jarPrefix();
  1342. String alloytxt;
  1343. try { alloytxt = Util.readAll(JAR + "LICENSES" + File.separator + "Alloy.txt"); } catch(IOException ex) { return null; }
  1344. final JTextArea text = OurUtil.textarea(alloytxt, 15, 85, false, false, new EmptyBorder(2, 2, 2, 2), new Font("Monospaced", Font.PLAIN, 12));
  1345. final JScrollPane scroll = OurUtil.scrollpane(text, new LineBorder(Color.DARK_GRAY, 1));
  1346. @SuppressWarnings("rawtypes")
  1347. final JComboBox combo = new OurCombobox(new String[]{"Alloy","Kodkod","JavaCup","SAT4J","ZChaff","MiniSat"}) {
  1348. private static final long serialVersionUID = 0;
  1349. @Override public void do_changed(Object value) {
  1350. if (value instanceof String) {
  1351. try {
  1352. String content = Util.readAll(JAR + "LICENSES" + File.separator + value + ".txt");
  1353. text.setText(content);
  1354. } catch(IOException ex) {
  1355. text.setText("Sorry: an error has occurred in displaying the license file.");
  1356. }
  1357. }
  1358. text.setCaretPosition(0);
  1359. }
  1360. };
  1361. OurDialog.showmsg("Copyright Notices",
  1362. "The source code for the Alloy Analyzer is available under the MIT license.",
  1363. " ",
  1364. "The Alloy Analyzer utilizes several third-party packages whose code may",
  1365. "be distributed under a different license. We are extremely grateful to",
  1366. "the authors of these packages for making their source code freely available.",
  1367. " ",
  1368. OurUtil.makeH(null, "See the copyright notice for: ", combo, null),
  1369. " ",
  1370. scroll
  1371. );
  1372. return null;
  1373. }
  1374. /** This method changes the latest instance. */
  1375. void doSetLatest(String arg) {
  1376. latestInstance = arg;
  1377. latestAutoInstance = arg;
  1378. }
  1379. /** The color to use for functions/predicate/paragraphs that contains part of the unsat core. */
  1380. final Color supCoreColor = new Color(0.95f, 0.1f, 0.1f);
  1381. /** The color to use for the unsat core. */
  1382. final Color coreColor = new Color(0.9f, 0.4f, 0.4f);
  1383. /** The color to use for functions/predicate used by the Unsat core. */
  1384. final Color subCoreColor = new Color(0.9f, 0.7f, 0.7f);
  1385. /** This method displays a particular instance or message. */
  1386. @SuppressWarnings("unchecked")
  1387. Runner doVisualize(String arg) {
  1388. if (wrap) return wrapMe(arg);
  1389. text.clearShade();
  1390. if (arg.startsWith("MSG: ")) { // MSG: message
  1391. OurDialog.showtext("Detailed Message", arg.substring(5));
  1392. }
  1393. if (arg.startsWith("CORE: ")) { // CORE: filename
  1394. String filename = Util.canon(arg.substring(6));
  1395. Pair<Set<Pos>,Set<Pos>> hCore;
  1396. @SuppressWarnings("unused")
  1397. Set<Pos> lCore;
  1398. InputStream is = null;
  1399. ObjectInputStream ois = null;
  1400. try {
  1401. is = new FileInputStream(filename);
  1402. ois = new ObjectInputStream(is);
  1403. hCore = (Pair<Set<Pos>,Set<Pos>>) ois.readObject();
  1404. lCore = (Set<Pos>) ois.readObject();
  1405. } catch(Throwable ex) {
  1406. log.logRed("Error reading or parsing the core \""+filename+"\"\n");
  1407. return null;
  1408. } finally {
  1409. Util.close(ois);
  1410. Util.close(is);
  1411. }
  1412. text.clearShade();
  1413. text.shade(hCore.b, subCoreColor, false);
  1414. text.shade(hCore.a, coreColor, false);
  1415. // shade again, because if not all files were open, some shadings will have no effect
  1416. text.shade(hCore.b, subCoreColor, false);
  1417. text.shade(hCore.a, coreColor, false);
  1418. }
  1419. if (arg.startsWith("POS: ")) { // POS: x1 y1 x2 y2 filename
  1420. @SuppressWarnings("resource")
  1421. Scanner s=new Scanner(arg.substring(5));
  1422. int x1=s.nextInt(), y1=s.nextInt(), x2=s.nextInt(), y2=s.nextInt();
  1423. String f=s.nextLine();
  1424. if (f.length()>0 && f.charAt(0)==' ') f=f.substring(1); // Get rid of the space after Y2
  1425. Pos p=new Pos(Util.canon(f), x1, y1, x2, y2);
  1426. text.shade(p);
  1427. }
  1428. if (arg.startsWith("CNF: ")) { // CNF: filename
  1429. String filename=Util.canon(arg.substring(5));
  1430. try { String text=Util.readAll(filename); OurDialog.showtext("Text Viewer", text); }
  1431. catch(IOException ex) { log.logRed("Error reading the file \""+filename+"\"\n"); }
  1432. }
  1433. if (arg.startsWith("XML: ")) { // XML: filename
  1434. viz.loadXML(Util.canon(arg.substring(5)), false);
  1435. }
  1436. return null;
  1437. }
  1438. /** This method opens a particular file. */
  1439. public Runner doOpenFile(String arg) {
  1440. if (wrap) return wrapMe(arg);
  1441. String f=Util.canon(arg);
  1442. if (!text.newtab(f)) return null;
  1443. if (text.get().isFile()) addHistory(f);
  1444. doShow();
  1445. text.get().requestFocusInWindow();
  1446. log.clearError();
  1447. return null;
  1448. }
  1449. /** This object performs solution enumeration. */
  1450. private final Computer enumerator = new Computer() {
  1451. public String compute(Object input) {
  1452. final String arg = (String)input;
  1453. if(isVisible) OurUtil.show(frame);
  1454. if (WorkerEngineCustom.isBusy())
  1455. throw new RuntimeException("Alloy4 is currently executing a SAT solver command. Please wait until that command has finished.");
  1456. SimpleCallback1 cb = new SimpleCallback1(SimpleGUICustom.this, viz, log, Verbosity.get().ordinal(), latestAlloyVersionName, latestAlloyVersion);
  1457. SimpleTask2 task = new SimpleTask2();
  1458. task.filename = arg;
  1459. try {
  1460. WorkerEngineCustom.run(task, SubMemory.get(), SubStack.get(), alloyHome() + fs + "binary","", cb);
  1461. //task.run(cb);
  1462. } catch(Throwable ex) {
  1463. WorkerEngineCustom.stop();
  1464. log.logBold("Fatal Error: Solver failed due to unknown reason.\n" +
  1465. "One possible cause is that, in the Options menu, your specified\n" +
  1466. "memory size is larger than the amount allowed by your OS.\n" +
  1467. "Also, please make sure \"java\" is in your program path.\n");
  1468. log.logDivider();
  1469. log.flush();
  1470. doStop(2);
  1471. return arg;
  1472. }
  1473. subrunningTask=2;
  1474. runmenu.setEnabled(false);
  1475. runbutton.setVisible(false);
  1476. showbutton.setEnabled(false);
  1477. stopbutton.setVisible(true);
  1478. return arg;
  1479. }
  1480. };
  1481. /** Converts an A4TupleSet into a SimTupleset object. */
  1482. private static SimTupleset convert(Object object) throws Err {
  1483. if (!(object instanceof A4TupleSet)) throw new ErrorFatal("Unexpected type error: expecting an A4TupleSet.");
  1484. A4TupleSet s = (A4TupleSet)object;
  1485. if (s.size()==0) return SimTupleset.EMPTY;
  1486. List<SimTuple> list = new ArrayList<SimTuple>(s.size());
  1487. int arity = s.arity();
  1488. for(A4Tuple t: s) {
  1489. String[] array = new String[arity];
  1490. for(int i=0; i<t.arity(); i++) array[i] = t.atom(i);
  1491. list.add(SimTuple.make(array));
  1492. }
  1493. return SimTupleset.make(list);
  1494. }
  1495. /** Converts an A4Solution into a SimInstance object. */
  1496. private static SimInstance convert(Module root, A4Solution ans) throws Err {
  1497. SimInstance ct = new SimInstance(root, ans.getBitwidth(), ans.getMaxSeq());
  1498. for(Sig s: ans.getAllReachableSigs()) {
  1499. if (!s.builtin) ct.init(s, convert(ans.eval(s)));
  1500. for(Field f: s.getFields()) if (!f.defined) ct.init(f, convert(ans.eval(f)));
  1501. }
  1502. for(ExprVar a:ans.getAllAtoms()) ct.init(a, convert(ans.eval(a)));
  1503. for(ExprVar a:ans.getAllSkolems()) ct.init(a, convert(ans.eval(a)));
  1504. return ct;
  1505. }
  1506. /** This object performs expression evaluation. */
  1507. private static Computer evaluator = new Computer() {
  1508. private String filename = null;
  1509. public final String compute(final Object input) throws Exception {
  1510. if (input instanceof File) { filename = ((File)input).getAbsolutePath(); return ""; }
  1511. if (!(input instanceof String)) return "";
  1512. final String str = (String)input;
  1513. if (str.trim().length()==0) return ""; // Empty line
  1514. Module root = null;
  1515. A4Solution ans = null;
  1516. try {
  1517. Map<String,String> fc = new LinkedHashMap<String,String>();
  1518. XMLNode x = new XMLNode(new File(filename));
  1519. if (!x.is("alloy")) throw new Exception();
  1520. String mainname=null;
  1521. for(XMLNode sub: x) if (sub.is("instance")) {
  1522. mainname=sub.getAttribute("filename");
  1523. break;
  1524. }
  1525. if (mainname==null) throw new Exception();
  1526. for(XMLNode sub: x) if (sub.is("source")) {
  1527. String name = sub.getAttribute("filename");
  1528. String content = sub.getAttribute("content");
  1529. fc.put(name, content);
  1530. }
  1531. root = CompUtil.parseEverything_fromFile(A4Reporter.NOP, fc, mainname, (Version.experimental && ImplicitThis.get()) ? 2 : 1);
  1532. ans = A4SolutionReader.read(root.getAllReachableSigs(), x);
  1533. for(ExprVar a:ans.getAllAtoms()) { root.addGlobal(a.label, a); }
  1534. for(ExprVar a:ans.getAllSkolems()) { root.addGlobal(a.label, a); }
  1535. } catch(Throwable ex) {
  1536. throw new ErrorFatal("Failed to read or parse the XML file.");
  1537. }
  1538. try {
  1539. Expr e = CompUtil.parseOneExpression_fromString(root, str);
  1540. if ("yes".equals(System.getProperty("debug")) && Verbosity.get()==Verbosity.FULLDEBUG) {
  1541. SimInstance simInst = convert(root, ans);
  1542. return simInst.visitThis(e).toString() + (simInst.wasOverflow() ? " (OF)" : "");
  1543. } else
  1544. return ans.eval(e).toString();
  1545. } catch(HigherOrderDeclException ex) {
  1546. throw new ErrorType("Higher-order quantification is not allowed in the evaluator.");
  1547. }
  1548. }
  1549. };
  1550. /** Returns true iff the output says "s SATISFIABLE" (while ignoring comment lines and value lines) */
  1551. private static boolean isSat(String output) {
  1552. int i=0, n=output.length();
  1553. // skip COMMENT lines and VALUE lines
  1554. while(i<n && (output.charAt(i)=='c' || output.charAt(i)=='v')) {
  1555. while(i<n && (output.charAt(i)!='\r' && output.charAt(i)!='\n')) i++;
  1556. while(i<n && (output.charAt(i)=='\r' || output.charAt(i)=='\n')) i++;
  1557. continue;
  1558. }
  1559. return output.substring(i).startsWith("s SATISFIABLE");
  1560. }
  1561. //====== Main Method ====================================================//
  1562. //.....
  1563. //====== Constructor ====================================================//
  1564. private static boolean loadLibrary(String library) {
  1565. try { System.loadLibrary(library); return true; } catch(UnsatisfiedLinkError ex) { }
  1566. try { System.loadLibrary(library+"x1"); return true; } catch(UnsatisfiedLinkError ex) { }
  1567. try { System.loadLibrary(library+"x2"); return true; } catch(UnsatisfiedLinkError ex) { }
  1568. try { System.loadLibrary(library+"x3"); return true; } catch(UnsatisfiedLinkError ex) { }
  1569. try { System.loadLibrary(library+"x4"); return true; } catch(UnsatisfiedLinkError ex) { }
  1570. try { System.loadLibrary(library+"x5"); return true; } catch(UnsatisfiedLinkError ex) { return false; }
  1571. }
  1572. /** Create a dummy task object for testing purpose. */
  1573. private static final WorkerEngineCustom.WorkerTaskCustom dummyTask = new WorkerEngineCustom.WorkerTaskCustom() {
  1574. private static final long serialVersionUID = 0;
  1575. public void run(WorkerCallbackCustom out) { }
  1576. };
  1577. /** Set this Frame Visible */
  1578. public void setVisible(boolean visible)
  1579. {
  1580. isVisible = visible;
  1581. if (visible) doShow();
  1582. }
  1583. public void setTheme(String theme)
  1584. {
  1585. themePath = theme;
  1586. }
  1587. /** The constructor; this method will be called by the AWT event thread, using the "invokeLater" method. */
  1588. public SimpleGUICustom (final String[] args, final boolean visible, final String themepath) {
  1589. isVisible = visible;
  1590. if(themepath!=null) themePath = themepath;
  1591. // Register an exception handler for uncaught exceptions
  1592. //MailBug.setup();
  1593. // Enable better look-and-feel
  1594. if (Util.onMac() || Util.onWindows()) {
  1595. //System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Alloy Analyzer "+Version.version());
  1596. System.setProperty("com.apple.mrj.application.growbox.intrudes","true");
  1597. System.setProperty("com.apple.mrj.application.live-resize","true");
  1598. //System.setProperty("com.apple.macos.useScreenMenuBar","true");
  1599. //System.setProperty("apple.laf.useScreenMenuBar","true");
  1600. //try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Throwable e) { }
  1601. }
  1602. // Figure out the desired x, y, width, and height
  1603. int screenWidth=OurUtil.getScreenWidth(), screenHeight=OurUtil.getScreenHeight();
  1604. int width=AnalyzerWidth.get();
  1605. if (width<=0) width=screenWidth/10*8; else if (width<100) width=100;
  1606. if (width>screenWidth) width=screenWidth;
  1607. int height=AnalyzerHeight.get();
  1608. if (height<=0) height=screenHeight/10*8; else if (height<100) height=100;
  1609. if (height>screenHeight) height=screenHeight;
  1610. int x=AnalyzerX.get(); if (x<0) x=screenWidth/10; if (x>screenWidth-100) x=screenWidth-100;
  1611. int y=AnalyzerY.get(); if (y<0) y=screenHeight/10; if (y>screenHeight-100) y=screenHeight-100;
  1612. // Put up a slash screen
  1613. final JFrame frame = new JFrame("Alloy Analyzer");
  1614. frame.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
  1615. frame.pack();
  1616. if (!Util.onMac() && !Util.onWindows()) {
  1617. String gravity = System.getenv("_JAVA_AWT_WM_STATIC_GRAVITY");
  1618. if (gravity==null || gravity.length()==0) {
  1619. // many Window managers do not respect ICCCM2; this should help avoid the Title Bar being shifted "off screen"
  1620. if (x<30) { if (x<0) x=0; width=width-(30-x); x=30; }
  1621. if (y<30) { if (y<0) y=0; height=height-(30-y); y=30; }
  1622. }
  1623. if (width<100) width=100;
  1624. if (height<100) height=100;
  1625. }
  1626. frame.setSize(width,height);
  1627. frame.setLocation(x,y);
  1628. frame.setVisible(isVisible);
  1629. frame.setTitle("Alloy Analyzer "+Version.version()+" loading... please wait...");
  1630. final int windowWidth = width;
  1631. // We intentionally call setVisible(true) first before settings the "please wait" title,
  1632. // since we want the minimized window title on Linux/FreeBSD to just say Alloy Analyzer
  1633. // Test the allowed memory sizes
  1634. final WorkerEngineCustom.WorkerCallbackCustom c = new WorkerEngineCustom.WorkerCallbackCustom() {
  1635. private final List<Integer> allowed = new ArrayList<Integer>();
  1636. private final List<Integer> toTry = new ArrayList<Integer>(Arrays.asList(256,512,768,1024,1536,2048,2560,3072,3584,4096));
  1637. private int mem;
  1638. public synchronized void callback(Object msg) {
  1639. if (toTry.size()==0) {
  1640. SwingUtilities.invokeLater(new Runnable() {
  1641. public void run() { SimpleGUICustom.this.frame=frame; SimpleGUICustom.this.finishInit(args, allowed, windowWidth); }
  1642. });
  1643. return;
  1644. }
  1645. try { mem=toTry.remove(0); WorkerEngineCustom.stop(); WorkerEngineCustom.run(dummyTask, mem, 128, "", "", this); return; } catch(IOException ex) { fail(); }
  1646. }
  1647. public synchronized void done() {
  1648. //System.out.println("Alloy4 can use "+mem+"M"); System.out.flush();
  1649. allowed.add(mem);
  1650. callback(null);
  1651. }
  1652. public synchronized void fail() {
  1653. //System.out.println("Alloy4 cannot use "+mem+"M"); System.out.flush();
  1654. callback(null);
  1655. }
  1656. };
  1657. c.callback(null);
  1658. }
  1659. private void finishInit(String[] args, List<Integer> initialAllowedMemorySizes, int width) {
  1660. frame.setIconImage(Toolkit.getDefaultToolkit().getImage(SimpleGUICustom.class.getResource("/resources/icons/x16/alloy/alloy.png")));
  1661. // Add the listeners
  1662. try {
  1663. wrap = true;
  1664. frame.addWindowListener(doQuit());
  1665. } finally {
  1666. wrap = false;
  1667. }
  1668. frame.addComponentListener(this);
  1669. // initialize the "allowed memory sizes" array
  1670. allowedMemorySizes = new ArrayList<Integer>(initialAllowedMemorySizes);
  1671. int newmem = SubMemory.get();
  1672. if (!allowedMemorySizes.contains(newmem)) {
  1673. int newmemlen = allowedMemorySizes.size();
  1674. if (allowedMemorySizes.contains(768) || newmemlen==0)
  1675. SubMemory.set(768); // a nice default value
  1676. else
  1677. SubMemory.set(allowedMemorySizes.get(newmemlen-1));
  1678. }
  1679. // Choose the appropriate font
  1680. int fontSize=FontSize.get();
  1681. String fontName=FontName.get();
  1682. while(true) {
  1683. if (!OurDialog.hasFont(fontName)) fontName="Lucida Grande"; else break;
  1684. if (!OurDialog.hasFont(fontName)) fontName="Verdana"; else break;
  1685. if (!OurDialog.hasFont(fontName)) fontName="Courier New"; else break;
  1686. if (!OurDialog.hasFont(fontName)) fontName="Lucida Grande";
  1687. break;
  1688. }
  1689. FontName.set(fontName);
  1690. // Copy required files from the JAR
  1691. copyFromJAR();
  1692. final String binary = alloyHome() + fs + "binary";
  1693. // Create the menu bar
  1694. JMenuBar bar = new JMenuBar();
  1695. try {
  1696. wrap = true;
  1697. filemenu = menu(bar, "&File", doRefreshFile());
  1698. editmenu = menu(bar, "&Edit", doRefreshEdit());
  1699. runmenu = menu(bar, "E&xecute", doRefreshRun());
  1700. optmenu = menu(bar, "&Options", doRefreshOption());
  1701. windowmenu = menu(bar, "&Window", doRefreshWindow(false));
  1702. windowmenu2 = menu(null, "&Window", doRefreshWindow(true));
  1703. helpmenu = menu(bar, "&Help", null);
  1704. if (!Util.onMac()) menuItem(helpmenu, "About Alloy...", 'A', doAbout());
  1705. menuItem(helpmenu, "Quick Guide", 'Q', doHelp());
  1706. menuItem(helpmenu, "See the Copyright Notices...", 'L', doLicense());
  1707. } finally {
  1708. wrap = false;
  1709. }
  1710. // Pre-load the visualizer
  1711. viz = new VizGUICustom(false, "", windowmenu2, enumerator, evaluator);
  1712. viz.doSetFontSize(FontSize.get());
  1713. // Create the toolbar
  1714. try {
  1715. wrap = true;
  1716. toolbar = new JToolBar();
  1717. toolbar.setFloatable(false);
  1718. if (!Util.onMac()) toolbar.setBackground(background);
  1719. toolbar.add(OurUtil.button("New", "Starts a new blank model", "images/24_new.gif", doNew()));
  1720. toolbar.add(OurUtil.button("Open", "Opens an existing model", "images/24_open.gif", doOpen()));
  1721. toolbar.add(OurUtil.button("Reload", "Reload all the models from disk", "images/24_reload.gif", doReloadAll()));
  1722. toolbar.add(OurUtil.button("Save", "Saves the current model", "images/24_save.gif", doSave()));
  1723. toolbar.add(runbutton=OurUtil.button("Execute", "Executes the latest command", "images/24_execute.gif", doExecuteLatest()));
  1724. toolbar.add(stopbutton=OurUtil.button("Stop", "Stops the current analysis", "images/24_execute_abort2.gif", doStop(2)));
  1725. stopbutton.setVisible(false);
  1726. toolbar.add(showbutton=OurUtil.button("Show", "Shows the latest instance", "images/24_graph.gif", doShowLatest()));
  1727. toolbar.add(Box.createHorizontalGlue());
  1728. toolbar.setBorder(new OurBorder(false,false,false,false));
  1729. } finally {
  1730. wrap = false;
  1731. }
  1732. // Choose the antiAlias setting
  1733. OurAntiAlias.enableAntiAlias(AntiAlias.get());
  1734. // Create the message area
  1735. logpane = OurUtil.scrollpane(null);
  1736. log = new SwingLogPanelCustom(logpane, fontName, fontSize, background, Color.BLACK, new Color(.7f,.2f,.2f), this);
  1737. // Create the text area
  1738. text = new OurTabbedSyntaxWidget(fontName, fontSize, TabSize.get());
  1739. text.listeners.add(this);
  1740. text.enableSyntax(! SyntaxDisabled.get());
  1741. // Add everything to the frame, then display the frame
  1742. Container all=frame.getContentPane();
  1743. all.setLayout(new BorderLayout());
  1744. all.removeAll();
  1745. JPanel lefthalf=new JPanel();
  1746. lefthalf.setLayout(new BorderLayout());
  1747. lefthalf.add(toolbar, BorderLayout.NORTH);
  1748. text.addTo(lefthalf, BorderLayout.CENTER);
  1749. splitpane = OurUtil.splitpane(JSplitPane.HORIZONTAL_SPLIT, lefthalf, logpane, width/2);
  1750. splitpane.setResizeWeight(0.5D);
  1751. status = OurUtil.make(OurAntiAlias.label(" "), new Font(fontName, Font.PLAIN, fontSize), Color.BLACK, background);
  1752. status.setBorder(new OurBorder(true,false,false,false));
  1753. all.add(splitpane, BorderLayout.CENTER);
  1754. all.add(status, BorderLayout.SOUTH);
  1755. // Generate some informative log messages
  1756. log.logBold("Alloy Analyzer "+Version.version()+" (build date: "+Version.buildDate()+")\n\n");
  1757. // If on Mac, then register an application listener
  1758. try {
  1759. wrap = true;
  1760. if (Util.onMac()) MacUtil.registerApplicationListener(doShow(), doAbout(), doOpenFile(""), doQuit());
  1761. } finally {
  1762. wrap = false;
  1763. }
  1764. // Add the new JNI location to the java.library.path
  1765. try {
  1766. System.setProperty("java.library.path", binary);
  1767. // The above line is actually useless on Sun JDK/JRE (see Sun's bug ID 4280189)
  1768. // The following 4 lines should work for Sun's JDK/JRE (though they probably won't work for others)
  1769. String[] newarray = new String[]{binary};
  1770. java.lang.reflect.Field old = ClassLoader.class.getDeclaredField("usr_paths");
  1771. old.setAccessible(true);
  1772. old.set(null,newarray);
  1773. } catch (Throwable ex) { }
  1774. // Testing the SAT solvers
  1775. if (true) {
  1776. satChoices = SatSolver.values().makeCopy();
  1777. // String test1 = Subprocess.exec(20000, new String[]{binary+fs+"berkmin", binary+fs+"tmp.cnf"});
  1778. // if (!isSat(test1)) satChoices.remove(SatSolver.BerkMinPIPE);
  1779. satChoices.remove(SatSolver.BerkMinPIPE);
  1780. String test2 = Subprocess.exec(20000, new String[]{binary+fs+"spear", "--model", "--dimacs", binary+fs+"tmp.cnf"});
  1781. if (!isSat(test2)) satChoices.remove(SatSolver.SpearPIPE);
  1782. if (!loadLibrary("minisat")) {
  1783. log.logBold("Warning: JNI-based SAT solver does not work on this platform.\n");
  1784. log.log("This is okay, since you can still use SAT4J as the solver.\n"+
  1785. "For more information, please visit http://alloy.mit.edu/alloy4/\n");
  1786. log.logDivider();
  1787. log.flush();
  1788. satChoices.remove(SatSolver.MiniSatJNI);
  1789. }
  1790. if (!loadLibrary("minisatprover")) satChoices.remove(SatSolver.MiniSatProverJNI);
  1791. if (!loadLibrary("zchaff")) satChoices.remove(SatSolver.ZChaffJNI);
  1792. SatSolver now = SatSolver.get();
  1793. if (!satChoices.contains(now)) {
  1794. now=SatSolver.ZChaffJNI;
  1795. if (!satChoices.contains(now)) now=SatSolver.SAT4J;
  1796. now.set();
  1797. }
  1798. if (now==SatSolver.SAT4J && satChoices.size()>3 && satChoices.contains(SatSolver.CNF) && satChoices.contains(SatSolver.KK)) {
  1799. log.logBold("Warning: Alloy4 defaults to SAT4J since it is pure Java and very reliable.\n");
  1800. log.log("For faster performance, go to Options menu and try another solver like MiniSat.\n");
  1801. log.log("If these native solvers fail on your computer, remember to change back to SAT4J.\n");
  1802. log.logDivider();
  1803. log.flush();
  1804. }
  1805. initialized=true;
  1806. }
  1807. // If the temporary directory has become too big, then tell the user they can "clear temporary directory".
  1808. long space = computeTemporarySpaceUsed();
  1809. if (space<0 || space>=20*1024768) {
  1810. if (space<0) log.logBold("Warning: Alloy4's temporary directory has exceeded 1024M.\n");
  1811. else log.logBold("Warning: Alloy4's temporary directory now uses "+(space/1024768)+"M.\n");
  1812. log.log("To clear the temporary directory,\n"
  1813. +"go to the File menu and click \"Clear Temporary Directory\"\n");
  1814. log.logDivider();
  1815. log.flush();
  1816. }
  1817. // Refreshes all the menu items
  1818. doRefreshFile(); OurUtil.enableAll(filemenu);
  1819. doRefreshEdit(); OurUtil.enableAll(editmenu);
  1820. doRefreshRun(); OurUtil.enableAll(runmenu);
  1821. doRefreshOption();
  1822. doRefreshWindow(false); OurUtil.enableAll(windowmenu);
  1823. frame.setJMenuBar(bar);
  1824. // Open the given file, if a filename is given in the command line
  1825. for(String f:args) if (f.toLowerCase(Locale.US).endsWith(".als")) {
  1826. File file = new File(f);
  1827. if (file.exists() && file.isFile()) doOpenFile(file.getPath());
  1828. }
  1829. // Update the title and status bar
  1830. notifyChange();
  1831. text.get().requestFocusInWindow();
  1832. // Launch the welcome screen if needed
  1833. // We do not need this when using it with OLED...
  1834. /*if (!"yes".equals(System.getProperty("debug")) && Welcome.get() < welcomeLevel) {
  1835. JCheckBox again = new JCheckBox("Show this message every time you start the Alloy Analyzer");
  1836. again.setSelected(true);
  1837. OurDialog.showmsg("Welcome",
  1838. "Thank you for using the Alloy Analyzer "+Version.version(),
  1839. " ",
  1840. "Version 4 of the Alloy Analyzer is a complete rewrite,",
  1841. "offering improvements in robustness, performance and usability.",
  1842. "Models written in Alloy 3 will require some small alterations to run in Alloy 4.",
  1843. " ",
  1844. "Here are some quick tips:",
  1845. " ",
  1846. "* Function calls now use [ ] instead of ( )",
  1847. " For more details, please see http://alloy.mit.edu/alloy4/quickguide/",
  1848. " ",
  1849. "* The Execute button always executes the latest command.",
  1850. " To choose which command to execute, go to the Execute menu.",
  1851. " ",
  1852. "* The Alloy Analyzer comes with a variety of sample models.",
  1853. " To see them, go to the File menu and click Open Sample Models.",
  1854. " ",
  1855. again
  1856. );
  1857. doShow();
  1858. if (!again.isSelected()) Welcome.set(welcomeLevel);
  1859. }*/
  1860. // Periodically ask the MailBug thread to see if there is a newer version or not
  1861. // final long now = System.currentTimeMillis();
  1862. // final Timer t = new Timer(800, null);
  1863. // t.addActionListener(new ActionListener() {
  1864. // public void actionPerformed(ActionEvent e) {
  1865. // int n = MailBug.latestBuildNumber();
  1866. // // If beyond 3 seconds, then we should stop because the log message may run into other user messages
  1867. // if (System.currentTimeMillis() - now >= 3000 || n <= Version.buildNumber()) { t.stop(); return; }
  1868. // latestAlloyVersion = n;
  1869. // latestAlloyVersionName = MailBug.latestBuildName();
  1870. // log.logBold("An updated version of the Alloy Analyzer has been released.\n");
  1871. // log.log("Please visit alloy.mit.edu to download the latest version:\nVersion " + latestAlloyVersionName + "\n");
  1872. // log.logDivider();
  1873. // log.flush();
  1874. // t.stop();
  1875. // }
  1876. // });
  1877. // t.start();
  1878. }
  1879. /** {@inheritDoc} */
  1880. public Object do_action(Object sender, Event e) {
  1881. if (sender instanceof OurTabbedSyntaxWidget) switch(e) {
  1882. case FOCUSED: notifyFocusGained(); break;
  1883. case STATUS_CHANGE: notifyChange(); break;
  1884. default:
  1885. break;
  1886. }
  1887. return true;
  1888. }
  1889. /** {@inheritDoc} */
  1890. public Object do_action(Object sender, Event e, Object arg) {
  1891. if (sender instanceof OurTree && e==Event.CLICK && arg instanceof Browsable) {
  1892. Pos p = ((Browsable)arg).pos();
  1893. if (p==Pos.UNKNOWN) p = ((Browsable)arg).span();
  1894. text.shade(p);
  1895. }
  1896. return true;
  1897. }
  1898. }