Skip to content
This repository
Browse code

Ctrl+c seems to be working on Windows now.

  • Loading branch information...
commit 576b9ace74a4719b27082b67f1ddbeabf55b4226 1 parent 134b05c
Caleb Eggensperger authored November 13, 2012
8  .gitignore
... ...
@@ -1,4 +1,3 @@
1  
-
2 1
 .DS_Store
3 2
 OrangeExtensions-1.2.jar
4 3
 bin/*
@@ -15,4 +14,9 @@ help/Proof Pad.help
15 14
 help/win
16 15
 help/mac
17 16
 user_data.dat
18  
-dracula/*
  17
+dracula/*
  18
+ctrl-c/ctrlc-windows/Debug/*
  19
+ctrl-c/ctrlc-windows/Release/*
  20
+ctrl-c/ctrlc-windows/*.sdf
  21
+ctrl-c/ctrlc-windows/*.opensdf
  22
+ctrl-c/ctrlc-windows/*.user
5  ctrl-c/ctrlc-windows/ctrlc-windows.cpp
@@ -137,7 +137,7 @@ BOOL Go(const char *commandLine)
137 137
 		NULL,          // process security attributes 
138 138
 		NULL,          // primary thread security attributes 
139 139
 		TRUE,          // handles are inherited 
140  
-		0,             // creation flags 
  140
+		CREATE_BREAKAWAY_FROM_JOB,             // creation flags 
141 141
 		NULL,          // use parent's environment 
142 142
 		NULL,          // use parent's current directory 
143 143
 		&siStartInfo,  // STARTUPINFO pointer 
@@ -157,7 +157,7 @@ BOOL Go(const char *commandLine)
157 157
 
158 158
 	if (!AssignProcessToJobObject( ghJob, piProcInfo.hProcess)) {
159 159
 		DWORD error = GetLastError();
160  
-		std::cerr << "AssignProcessToJobObject failed" << std::endl;
  160
+		std::cerr << "AssignProcessToJobObject failed: " << error << std::endl;
161 161
 		return FALSE;
162 162
 	}
163 163
 
@@ -166,7 +166,6 @@ BOOL Go(const char *commandLine)
166 166
 	// of the child process, for example. 
167 167
 
168 168
 	CloseHandle(piProcInfo.hThread);
169  
-	
170 169
 	MonitorProcessClose(piProcInfo.hProcess);
171 170
 
172 171
 	WriteToPipe(stdInWrite, piProcInfo.hProcess);
2  ctrl-c/ctrlc-windows/ctrlc-windows.vcxproj
@@ -20,12 +20,14 @@
20 20
     <ConfigurationType>Application</ConfigurationType>
21 21
     <UseDebugLibraries>true</UseDebugLibraries>
22 22
     <CharacterSet>NotSet</CharacterSet>
  23
+    <PlatformToolset>v110</PlatformToolset>
23 24
   </PropertyGroup>
24 25
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
25 26
     <ConfigurationType>Application</ConfigurationType>
26 27
     <UseDebugLibraries>false</UseDebugLibraries>
27 28
     <WholeProgramOptimization>true</WholeProgramOptimization>
28 29
     <CharacterSet>NotSet</CharacterSet>
  30
+    <PlatformToolset>v110</PlatformToolset>
29 31
   </PropertyGroup>
30 32
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
31 33
   <ImportGroup Label="ExtensionSettings">
BIN  ctrlc-windows.exe
Binary file not shown
41  src/org/proofpad/Acl2.java
@@ -173,20 +173,18 @@ public void run() {
173 173
 							try {
174 174
 								out.flush();
175 175
 							} catch (IOException e) {
176  
-								e.printStackTrace();
  176
+//								e.printStackTrace();
177 177
 							}
178 178
 						}
179 179
 					}).start();
180 180
 					if (lastAdmittedTimestamp < System.currentTimeMillis() - ACL2_IS_SLOW_DELAY &&
181  
-							!acl2IsSlowShown && !callbacks.isEmpty()
182  
-							&& !Main.WIN /* TODO: Remove this when ctrl+C on Windows is fixed */
183  
-							) {
  181
+							!acl2IsSlowShown && !callbacks.isEmpty()) {
184 182
 						acl2IsSlowShown = true;
185 183
 						currentInfobar = fireErrorEvent("ACL2 is taking a while.", new InfoButton[] {
186 184
 								new InfoButton("Interrupt",
187 185
 									new ActionListener() {
188 186
 										@Override public void actionPerformed(ActionEvent arg0) {
189  
-											interrupt();
  187
+											ctrlc();
190 188
 										}
191 189
 									})});
192 190
 						currentInfobar.addCloseListener(new CloseListener() {
@@ -242,7 +240,7 @@ public void run() {
242 240
 						}
243 241
 					}
244 242
 				} catch (Exception e) {
245  
-					e.printStackTrace();
  243
+//					e.printStackTrace();
246 244
 					failAllCallbacks();
247 245
 					fireRestartEvent();
248 246
 					showAcl2TerminatedError();
@@ -305,9 +303,10 @@ public void initialize() throws IOException {
305 303
 		acl2IsSlowShown = false;
306 304
 
307 305
 		for (String maybeAcl2Path : acl2Paths) {
  306
+			if (!new File(maybeAcl2Path).exists()) continue;
  307
+			System.out.println(maybeAcl2Path);
308 308
 			if (Main.WIN) {
309  
-				//processBuilder = new ProcessBuilder("ctrlc-windows.exe", acl2Path);
310  
-				processBuilder = new ProcessBuilder(maybeAcl2Path);
  309
+				processBuilder = new ProcessBuilder("C:\\Users\\calebegg\\Documents\\GitHub\\proof-pad\\ctrlc-windows.exe", maybeAcl2Path);
311 310
 			} else {
312 311
 				processBuilder = new ProcessBuilder("sh", "-c", "echo \"$$\"; exec \"$0\" \"$@\"" + maybeAcl2Path);
313 312
 			}
@@ -322,6 +321,7 @@ public void initialize() throws IOException {
322 321
 				acl2 = processBuilder.start();
323 322
 			} catch (IOException e) {
324 323
 				// Try the next path
  324
+				e.printStackTrace();
325 325
 				continue;
326 326
 			}
327 327
 			acl2Path = maybeAcl2Path;
@@ -429,20 +429,20 @@ private void fireRestartEvent() {
429 429
 	}
430 430
 	
431 431
 	public void terminate() {
  432
+		if (acl2 == null) return;
432 433
 		admit("(good-bye)", Acl2.doNothingCallback);
433 434
 		if (Main.WIN) {
434  
-			// Depends on ctrlc-windows.exe
435  
-//			try {
436  
-//				out.write(0);
437  
-//				out.flush();
438  
-//			} catch (IOException e) { }
  435
+			try {
  436
+				out.write(0);
  437
+				out.flush();
  438
+			} catch (IOException e) { }
439 439
 		}
440 440
 		new Thread(new Runnable() {
441 441
 			@Override public void run() {
442 442
 				try {
443 443
 					sleep(5000);
444 444
 				} catch (InterruptedException e) { }
445  
-				Acl2.this.interrupt();
  445
+				Acl2.this.ctrlc();
446 446
 			}
447 447
 		}).start();
448 448
 		try {
@@ -451,13 +451,18 @@ public void terminate() {
451 451
 			acl2.destroy();
452 452
 		}
453 453
 	}
  454
+
  455
+	private void writeByte(int b) {
  456
+		try {
  457
+			out.write(b);
  458
+			out.flush();
  459
+		} catch (IOException e) { }
  460
+	}
454 461
 	
455  
-	@Override
456  
-	public void interrupt() {
  462
+	public void ctrlc() {
457 463
 		backoff = 0;
458 464
 		if (Main.WIN) {
459  
-			// Depends on ctrlc-windows.exe
460  
-			//writeByte(1);
  465
+			writeByte(1);
461 466
 		} else {
462 467
 			try {
463 468
 				Runtime.getRuntime().exec(new String[] {"kill", "-s", "INT", Integer.toString(procId)});
4  src/org/proofpad/IdeWindow.java
@@ -301,7 +301,9 @@ public void wasParsed() {
301 301
 			JOptionPane.showMessageDialog(this, "ACL2 executable not found",
302 302
 					"Error", JOptionPane.ERROR_MESSAGE);
303 303
 		}
304  
-		parser.setAcl2Dir(new File(acl2.getAcl2Path()).getParentFile());
  304
+		if (acl2.getAcl2Path() != null) {
  305
+			parser.setAcl2Dir(new File(acl2.getAcl2Path()).getParentFile());
  306
+		}
305 307
 
306 308
 		undoAction = new ActionListener() {
307 309
 			@Override
1,080  src/org/proofpad/MenuBar.java
... ...
@@ -1,541 +1,539 @@
1  
-package org.proofpad;
2  
-
3  
-import java.awt.Desktop;
4  
-import java.awt.Frame;
5  
-import java.awt.Toolkit;
6  
-import java.awt.event.ActionEvent;
7  
-import java.awt.event.ActionListener;
8  
-import java.awt.event.KeyEvent;
9  
-import java.io.File;
10  
-import java.io.IOException;
11  
-import java.net.URI;
12  
-import java.util.prefs.Preferences;
13  
-
14  
-import javax.swing.ButtonGroup;
15  
-import javax.swing.JMenu;
16  
-import javax.swing.JMenuBar;
17  
-import javax.swing.JMenuItem;
18  
-import javax.swing.JOptionPane;
19  
-import javax.swing.JRadioButtonMenuItem;
20  
-import javax.swing.KeyStroke;
21  
-import javax.swing.text.BadLocationException;
22  
-import javax.swing.text.DefaultEditorKit;
23  
-
24  
-import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaEditorKit;
25  
-
26  
-public class MenuBar extends JMenuBar {
27  
-	static final int RECENT_MENU_ITEMS = 10;
28  
-	private static final boolean WIN = Main.WIN || Main.FAKE_WINDOWS;
29  
-	private static final boolean OSX = Main.OSX && !Main.FAKE_WINDOWS;
30  
-	private static final boolean TITLE_CASE = !WIN;
31  
-	private static final long serialVersionUID = -3469258243341307842L;
32  
-	static final int modKey = Main.FAKE_WINDOWS ? KeyEvent.CTRL_DOWN_MASK : Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
33  
-	public JMenuItem undo;
34  
-	public JMenuItem redo;
35  
-	private JMenu windowMenu;
36  
-	protected Frame parent;
37  
-	public JMenuItem saveItem;
38  
-	JMenu recentMenu;
39  
-	JMenuItem parentItem;
40  
-
41  
-	public MenuBar(final IdeWindow parent) {
42  
-		this.parent = parent;
43  
-		
44  
-		final ActionListener prefsAction = new ActionListener() {
45  
-			@Override
46  
-			public void actionPerformed(ActionEvent e) {
47  
-				if (IdeWindow.prefsWindow == null) {
48  
-					IdeWindow.prefsWindow = new PrefsWindow();
49  
-				}
50  
-				IdeWindow.prefsWindow.setVisible(true);
51  
-			}
52  
-		};
53  
-		
54  
-		JMenu menu = new JMenu("File");
55  
-		JMenuItem item = new JMenuItem("New");
56  
-		item.addActionListener(new ActionListener() {
57  
-			@Override
58  
-			public void actionPerformed(ActionEvent e) {
59  
-				IdeWindow window = new IdeWindow();
60  
-				window.setVisible(true);
61  
-			}
62  
-		});
63  
-		item.addActionListener(new UserData.LogUse("newMenuItem"));
64  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, modKey));
65  
-		menu.add(item);
66  
-		
67  
-		item = new JMenuItem("Open...");
68  
-		item.addActionListener(IdeWindow.openAction);
69  
-		item.addActionListener(new UserData.LogUse("openMenuItem"));
70  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, modKey));
71  
-		menu.add(item);
72  
-		recentMenu = new JMenu(applyTitleCase("Open recent"));
73  
-		updateRecentMenu();
74  
-		menu.add(recentMenu);
75  
-		
76  
-		menu.addSeparator();
77  
-		
78  
-		item = new JMenuItem("Close");
79  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, modKey));
80  
-		if (parent == null) {
81  
-			item.setEnabled(false);
82  
-		}
83  
-		item.addActionListener(new ActionListener() {
84  
-			@Override
85  
-			public void actionPerformed(ActionEvent e) {
86  
-				if (parent != null && parent.promptIfUnsavedAndClose()) {
87  
-					IdeWindow.updateWindowMenu();
88  
-				}
89  
-			}
90  
-		});
91  
-		item.addActionListener(new UserData.LogUse("closeMenuItem"));
92  
-		menu.add(item);
93  
-		
94  
-		item = new JMenuItem("Save");
95  
-		saveItem = item;
96  
-		if (parent == null) {
97  
-			item.setEnabled(false);
98  
-		} else {
99  
-			item.addActionListener(parent.saveAction);
100  
-			item.addActionListener(new UserData.LogUse("saveMenuItem"));
101  
-		}
102  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, modKey));
103  
-		menu.add(item);
104  
-		
105  
-		item = new JMenuItem("Duplicate");
106  
-		if (parent == null) {
107  
-			item.setEnabled(false);
108  
-		} else {
109  
-			item.addActionListener(new ActionListener(){
110  
-				@Override
111  
-				public void actionPerformed(ActionEvent e) {
112  
-					IdeWindow dupWin = new IdeWindow(parent.editor.getText());
113  
-					dupWin.setVisible(true);
114  
-				}
115  
-			});
116  
-			item.addActionListener(new UserData.LogUse("duplicateMenuItem"));
117  
-		}
118  
-		menu.add(item);
119  
-
120  
-		menu.addSeparator();
121  
-		
122  
-		item = new JMenuItem("Print...");
123  
-		if (parent == null)  {
124  
-			item.setEnabled(false);
125  
-		} else {
126  
-			item.addActionListener(parent.printAction);
127  
-			item.addActionListener(new UserData.LogUse("printMenuItem"));
128  
-		}
129  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, modKey));
130  
-		menu.add(item);
131  
-		
132  
-		if (!OSX) {
133  
-			menu.addSeparator();
134  
-			item = new JMenuItem(WIN ? "Exit" : "Quit");
135  
-			item.addActionListener(new ActionListener() {
136  
-				@Override
137  
-				public void actionPerformed(ActionEvent e) {
138  
-					new UserData.LogUse("quitMenuItem").actionPerformed(e);
139  
-					for (IdeWindow w : IdeWindow.windows) {
140  
-						w.promptIfUnsavedAndClose();
141  
-					}
142  
-				}
143  
-			});
144  
-			if (!WIN) {
145  
-				item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, modKey));
146  
-			}
147  
-			menu.add(item);
148  
-		}
149  
-		
150  
-		add(menu);
151  
-		
152  
-		/* ******* Edit Menu ******* */
153  
-		menu = new JMenu("Edit");
154  
-		item = new JMenuItem("Undo");
155  
-		undo = item;
156  
-		if (parent == null) {
157  
-			item.setEnabled(false);
158  
-		} else {
159  
-			item.addActionListener(parent.undoAction);
160  
-			item.addActionListener(new UserData.LogUse("undoMenuItem"));
161  
-		}
162  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, modKey));
163  
-		menu.add(item);
164  
-		
165  
-		item = new JMenuItem("Redo");
166  
-		redo = item;
167  
-		if (parent == null) {
168  
-			item.setEnabled(false);
169  
-		} else {
170  
-			item.addActionListener(parent.redoAction);
171  
-			item.addActionListener(new UserData.LogUse("redoMenuItem"));
172  
-		}
173  
-		if (OSX) {
174  
-			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, modKey | KeyEvent.SHIFT_DOWN_MASK));
175  
-		} else {
176  
-			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, modKey));
177  
-		}
178  
-		menu.add(item);
179  
-		
180  
-		menu.addSeparator();
181  
-		
182  
-		item = new JMenuItem(new DefaultEditorKit.CutAction());
183  
-		item.setText("Cut");
184  
-		item.setEnabled(parent != null);
185  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, modKey));
186  
-		item.addActionListener(new UserData.LogUse("cutMenuItem"));
187  
-		menu.add(item);
188  
-		
189  
-		item = new JMenuItem(new DefaultEditorKit.CopyAction());
190  
-		item.setText("Copy");
191  
-		item.setEnabled(parent != null);
192  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, modKey));
193  
-		item.addActionListener(new UserData.LogUse("copyMenuItem"));
194  
-		menu.add(item);
195  
-		
196  
-		item = new JMenuItem(new DefaultEditorKit.PasteAction());
197  
-		item.setText("Paste");
198  
-		item.setEnabled(parent != null);
199  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, modKey));
200  
-		item.addActionListener(new UserData.LogUse("pasteMenuItem"));
201  
-		menu.add(item);
202  
-		
203  
-		item = new JMenuItem("Delete");
204  
-		if (parent == null) {
205  
-			item.setEnabled(false);
206  
-		} else {
207  
-			item.addActionListener(new ActionListener() {
208  
-				@Override
209  
-				public void actionPerformed(ActionEvent e) {
210  
-					try {
211  
-						int selStart = parent.editor.getSelectionStart();
212  
-						int selEnd = parent.editor.getSelectionEnd();
213  
-						parent.editor.getDocument().remove(selStart, selEnd - selStart);
214  
-					} catch (BadLocationException e1) { }
215  
-				}
216  
-			});
217  
-			item.addActionListener(new UserData.LogUse("deleteMenuItem"));
218  
-		}
219  
-		menu.add(item);
220  
-		
221  
-		item = new JMenuItem(applyTitleCase("Select all"));
222  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, modKey));
223  
-		if (parent == null) {
224  
-			item.setEnabled(false);
225  
-		} else {
226  
-			item.addActionListener(new ActionListener() {
227  
-				@Override
228  
-				public void actionPerformed(ActionEvent arg0) {
229  
-					parent.editor.selectAll();
230  
-				}
231  
-			});
232  
-			item.addActionListener(new UserData.LogUse("selectAllMenuItem"));
233  
-		}
234  
-		
235  
-		menu.addSeparator();
236  
-		
237  
-		item = new JMenuItem("Find");
238  
-		if (parent == null) {
239  
-			item.setEnabled(false);
240  
-		} else {
241  
-			item.addActionListener(parent.findAction);
242  
-			item.addActionListener(new UserData.LogUse("findMenuItem"));
243  
-		}
244  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, modKey));
245  
-		menu.add(item);
246  
-		
247  
-		menu.addSeparator();
248  
-		
249  
-		item = new JMenuItem(applyTitleCase("Toggle comment"));
250  
-		item.setEnabled(parent != null);
251  
-		item.addActionListener(new RSyntaxTextAreaEditorKit.ToggleCommentAction());
252  
-		item.addActionListener(new UserData.LogUse("toggleCommentMenuItem"));
253  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_SEMICOLON, modKey));
254  
-		menu.add(item);
255  
-		item = new JMenuItem(applyTitleCase("Reindent selection"));
256  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, modKey));
257  
-		if (parent == null) {
258  
-			item.setEnabled(false);
259  
-		} else {
260  
-			item.addActionListener(parent.reindentAction);
261  
-			item.addActionListener(new UserData.LogUse("reindentMenuItem"));
262  
-		}
263  
-		menu.add(item);
264  
-		if (!OSX && !WIN) {
265  
-			menu.addSeparator();
266  
-			item = new JMenuItem("Preferences...");
267  
-			item.addActionListener(prefsAction);
268  
-			item.addActionListener(new UserData.LogUse("preferencesMenuItem"));
269  
-			menu.add(item);
270  
-		}
271  
-		add(menu);
272  
-		/* ******* ACL2 Menu ******* */
273  
-		menu = new JMenu("Tools");
274  
-		item = new JMenuItem("Restart ACL2");
275  
-		item.setEnabled(parent != null);
276  
-		item.addActionListener(new ActionListener() {
277  
-			@Override
278  
-			public void actionPerformed(ActionEvent arg0) {
279  
-				if (parent == null) return;
280  
-				try {
281  
-					parent.acl2.restart();
282  
-					parent.proofBar.resetProgress();
283  
-				} catch (IOException e) {
284  
-					JOptionPane.showMessageDialog(parent, "ACL2 executable not found", "Error",
285  
-							JOptionPane.ERROR_MESSAGE);
286  
-				}
287  
-			}
288  
-		});
289  
-		item.addActionListener(new UserData.LogUse("restartAcl2MenuItem"));
290  
-		menu.add(item);
291  
-		item = new JMenuItem("Interrupt ACL2");
292  
-		if (parent == null) {
293  
-			item.setEnabled(false);
294  
-		} else {
295  
-			item.addActionListener(new ActionListener() {
296  
-				@Override
297  
-				public void actionPerformed(ActionEvent e) {
298  
-					if (parent.acl2 != null && parent.acl2.isAlive()) {
299  
-						parent.acl2.interrupt();
300  
-					}
301  
-				}
302  
-			});
303  
-			item.addActionListener(new UserData.LogUse("interruptAcl2MenuItem"));
304  
-		}
305  
-		if (OSX) {
306  
-			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK));
307  
-		} else {
308  
-			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_K, modKey));
309  
-		}
310  
-		if (!WIN) {
311  
-			menu.add(item);
312  
-		}
313  
-		menu.addSeparator();
314  
-		item = new JMenuItem(applyTitleCase("Admit next item"));
315  
-		if (OSX) {
316  
-			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,
317  
-					modKey | KeyEvent.ALT_DOWN_MASK));
318  
-		} else {
319  
-			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, modKey));
320  
-		}
321  
-		if (parent == null) {
322  
-			item.setEnabled(false);
323  
-		} else {
324  
-			item.addActionListener(parent.admitNextAction);
325  
-			item.addActionListener(new UserData.LogUse("admitNextMenuItem"));
326  
-		}
327  
-		menu.add(item);
328  
-		item = new JMenuItem(applyTitleCase("Un-admit one item"));
329  
-		if (OSX) {
330  
-			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_UP,
331  
-					modKey | KeyEvent.ALT_DOWN_MASK));
332  
-		} else {
333  
-			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_UP, modKey));
334  
-		}
335  
-		if (parent == null) {
336  
-			item.setEnabled(false);
337  
-		} else {
338  
-			item.addActionListener(parent.undoPrevAction);
339  
-			item.addActionListener(new UserData.LogUse("unAdmitOneMenuItem"));
340  
-		}
341  
-		menu.add(item);
342  
-		menu.addSeparator();
343  
-		item = new JMenuItem(applyTitleCase("Clear REPL scrollback"));
344  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, modKey));
345  
-		if (parent == null) {
346  
-			item.setEnabled(false);
347  
-		} else {
348  
-			item.addActionListener(parent.clearReplScrollback);
349  
-			item.addActionListener(new UserData.LogUse("clearScrollbackMenuItem"));
350  
-		}
351  
-		menu.add(item);
352  
-		menu.addSeparator();
353  
-		item = new JMenuItem("Build");
354  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, modKey));
355  
-		if (parent == null) {
356  
-			item.setEnabled(false);
357  
-		} else {
358  
-			item.addActionListener(parent.buildAction);
359  
-			item.addActionListener(new UserData.LogUse("buildMenuItem"));
360  
-		}
361  
-		menu.add(item);
362  
-		menu.addSeparator();
363  
-		item = new JMenuItem(applyTitleCase("Include book..."));
364  
-		if (parent == null) {
365  
-			item.setEnabled(false);
366  
-		} else {
367  
-			item.addActionListener(parent.includeBookAction);
368  
-			item.addActionListener(new UserData.LogUse("includeBookMenuItem"));
369  
-		}
370  
-		menu.add(item);
371  
-		add(menu);
372  
-		if (WIN) {
373  
-			item = new JMenuItem("Options...");
374  
-			item.addActionListener(prefsAction);
375  
-			item.addActionListener(new UserData.LogUse("prefsMenuItem"));
376  
-			menu.addSeparator();
377  
-			menu.add(item);
378  
-		}
379  
-		/* ******* Window Menu (Mac only) ******* */
380  
-		if (OSX) {
381  
-			menu = new JMenu("Window");
382  
-			windowMenu = menu;
383  
-			add(menu);
384  
-			updateWindowMenu();
385  
-		}
386  
-		/* ******* */
387  
-		menu = new JMenu(OSX ? "Help " : "Help");
388  
-		item = new JMenuItem("Index");
389  
-		item = new JMenuItem(applyTitleCase("Quick guide"));
390  
-		item = new JMenuItem("Look up...");
391  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, modKey | KeyEvent.ALT_DOWN_MASK));
392  
-		if (parent == null) {
393  
-			item.setEnabled(false);
394  
-		} else {
395  
-			item.addActionListener(parent.helpAction);
396  
-			item.addActionListener(new UserData.LogUse("lookUpMenuItem"));
397  
-		}
398  
-		menu.add(item);
399  
-		item = new JMenuItem("Tutorial");
400  
-		if (parent == null) {
401  
-			item.setEnabled(false);
402  
-		} else {
403  
-			item.addActionListener(parent.tutorialAction);
404  
-			item.addActionListener(new UserData.LogUse("tutorialMenuItem"));
405  
-		}
406  
-		menu.add(item);
407  
-		menu.addSeparator();
408  
-		item = new JMenuItem(applyTitleCase("Report a bug"));
409  
-		item.addActionListener(new ActionListener() {
410  
-			@Override
411  
-			public void actionPerformed(ActionEvent e) {
412  
-				try {
413  
-					Desktop.getDesktop().browse(new URI("https://github.com/calebegg/proof-pad/issues/new"));
414  
-				} catch (Exception ex) { }
415  
-			}
416  
-		});
417  
-		item.addActionListener(new UserData.LogUse("reportBugMenuItem"));
418  
-		menu.add(item);
419  
-		if (!OSX) {
420  
-			item = new JMenuItem("About");
421  
-			item.addActionListener(new ActionListener() {
422  
-				@Override
423  
-				public void actionPerformed(ActionEvent e) {
424  
-					new AboutWindow().setVisible(true);
425  
-				}
426  
-			});
427  
-			item.addActionListener(new UserData.LogUse("aboutMenuItem"));
428  
-			menu.add(item);
429  
-		}
430  
-		add(menu);
431  
-	}
432  
-
433  
-	public void updateRecentMenu() {
434  
-		recentMenu.removeAll();
435  
-		final Preferences prefs = Preferences.userNodeForPackage(Main.class);
436  
-		for (int i = 1; i <= RECENT_MENU_ITEMS; i++) {
437  
-			String path = prefs.get("recent" + i, null);
438  
-			if (path == null) {
439  
-				break;
440  
-			}
441  
-			final File file = new File(path);
442  
-			JMenuItem item = new JMenuItem(file.getName());
443  
-			item.addActionListener(new ActionListener() {
444  
-				@Override
445  
-				public void actionPerformed(ActionEvent e) {
446  
-					new IdeWindow(file).setVisible(true);
447  
-				}
448  
-			});
449  
-			item.addActionListener(new UserData.LogUse("recentFileMenuItem"));
450  
-			recentMenu.add(item);
451  
-		}
452  
-		
453  
-		recentMenu.setEnabled(recentMenu.getItemCount() > 0);
454  
-		
455  
-		JMenuItem clearItem = new JMenuItem("Clear Menu");
456  
-		clearItem.addActionListener(new ActionListener() {
457  
-			@Override
458  
-			public void actionPerformed(ActionEvent e) {
459  
-				for (int i = 1; i <= RECENT_MENU_ITEMS; i++) {
460  
-					prefs.remove("recent" + i);
461  
-				}
462  
-				for (IdeWindow w : IdeWindow.windows) {
463  
-					w.menuBar.updateRecentMenu();
464  
-				}
465  
-			}
466  
-		});
467  
-		clearItem.addActionListener(new UserData.LogUse("clearRecentMenuItem"));
468  
-		recentMenu.addSeparator();
469  
-		recentMenu.add(clearItem);
470  
-	}
471  
-
472  
-	public void updateWindowMenu() {
473  
-		if (!OSX) return;
474  
-		windowMenu.removeAll();
475  
-		JMenuItem item = new JMenuItem();
476  
-		item = new JMenuItem("Minimize");
477  
-		item.setEnabled(parent != null);
478  
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, modKey));
479  
-		item.addActionListener(new ActionListener() {
480  
-			@Override
481  
-			public void actionPerformed(ActionEvent arg0) {
482  
-				parent.setState(Frame.ICONIFIED);
483  
-			}
484  
-		});
485  
-		item.addActionListener(new UserData.LogUse("minimizeMenuItem"));
486  
-		windowMenu.add(item);
487  
-		item = new JMenuItem("Zoom");
488  
-		item.setEnabled(parent != null);
489  
-		item.addActionListener(new ActionListener() {
490  
-			@Override
491  
-			public void actionPerformed(ActionEvent e) {
492  
-				if (parent.getState() == Frame.MAXIMIZED_BOTH) {
493  
-					parent.setState(Frame.NORMAL);
494  
-				} else {
495  
-					parent.setState(Frame.MAXIMIZED_BOTH);
496  
-				}
497  
-			}
498  
-		});
499  
-		item.addActionListener(new UserData.LogUse("zoomMenuItem"));
500  
-		windowMenu.add(item);
501  
-		if (IdeWindow.windows.size() <= 0) {
502  
-			return;
503  
-		}
504  
-		windowMenu.addSeparator();
505  
-		final ButtonGroup winItems = new ButtonGroup();
506  
-		for (final IdeWindow win : IdeWindow.windows) {
507  
-			JRadioButtonMenuItem winItem = new JRadioButtonMenuItem(win.getTitle(), win.isFocused());
508  
-			winItems.add(winItem);
509  
-			if (win == parent) {
510  
-				winItem.setSelected(true);
511  
-				parentItem = winItem;
512  
-			}
513  
-			winItem.addActionListener(new ActionListener() {
514  
-				@Override
515  
-				public void actionPerformed(ActionEvent arg0) {
516  
-					win.toFront();
517  
-					parentItem.setSelected(true);
518  
-				}
519  
-			});
520  
-			item.addActionListener(new UserData.LogUse("windowSwitchMenuItem"));
521  
-			windowMenu.add(winItem);
522  
-		}
523  
-	}
524  
-	
525  
-	private static String applyTitleCase(String phrase) {
526  
-		if (!TITLE_CASE || phrase.isEmpty()) {
527  
-			return phrase;
528  
-		}
529  
-		
530  
-		char[] cs = phrase.toCharArray();
531  
-		boolean afterSpace = false;
532  
-		for (int i = 0; i < cs.length; i++) {
533  
-			if (afterSpace && cs[i]>='a' && cs[i]<='z') {
534  
-				cs[i] += 'A'-'a';
535  
-			}
536  
-			afterSpace = cs[i]==' ';
537  
-		}
538  
-		return new String(cs);
539  
-	}
540  
-
541  
-}
  1
+package org.proofpad;
  2
+
  3
+import java.awt.Desktop;
  4
+import java.awt.Frame;
  5
+import java.awt.Toolkit;
  6
+import java.awt.event.ActionEvent;
  7
+import java.awt.event.ActionListener;
  8
+import java.awt.event.KeyEvent;
  9
+import java.io.File;
  10
+import java.io.IOException;
  11
+import java.net.URI;
  12
+import java.util.prefs.Preferences;
  13
+
  14
+import javax.swing.ButtonGroup;
  15
+import javax.swing.JMenu;
  16
+import javax.swing.JMenuBar;
  17
+import javax.swing.JMenuItem;
  18
+import javax.swing.JOptionPane;
  19
+import javax.swing.JRadioButtonMenuItem;
  20
+import javax.swing.KeyStroke;
  21
+import javax.swing.text.BadLocationException;
  22
+import javax.swing.text.DefaultEditorKit;
  23
+
  24
+import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaEditorKit;
  25
+
  26
+public class MenuBar extends JMenuBar {
  27
+	static final int RECENT_MENU_ITEMS = 10;
  28
+	private static final boolean WIN = Main.WIN || Main.FAKE_WINDOWS;
  29
+	private static final boolean OSX = Main.OSX && !Main.FAKE_WINDOWS;
  30
+	private static final boolean TITLE_CASE = !WIN;
  31
+	private static final long serialVersionUID = -3469258243341307842L;
  32
+	static final int modKey = Main.FAKE_WINDOWS ? KeyEvent.CTRL_DOWN_MASK : Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
  33
+	public JMenuItem undo;
  34
+	public JMenuItem redo;
  35
+	private JMenu windowMenu;
  36
+	protected Frame parent;
  37
+	public JMenuItem saveItem;
  38
+	JMenu recentMenu;
  39
+	JMenuItem parentItem;
  40
+
  41
+	public MenuBar(final IdeWindow parent) {
  42
+		this.parent = parent;
  43
+		
  44
+		final ActionListener prefsAction = new ActionListener() {
  45
+			@Override
  46
+			public void actionPerformed(ActionEvent e) {
  47
+				if (IdeWindow.prefsWindow == null) {
  48
+					IdeWindow.prefsWindow = new PrefsWindow();
  49
+				}
  50
+				IdeWindow.prefsWindow.setVisible(true);
  51
+			}
  52
+		};
  53
+		
  54
+		JMenu menu = new JMenu("File");
  55
+		JMenuItem item = new JMenuItem("New");
  56
+		item.addActionListener(new ActionListener() {
  57
+			@Override
  58
+			public void actionPerformed(ActionEvent e) {
  59
+				IdeWindow window = new IdeWindow();
  60
+				window.setVisible(true);
  61
+			}
  62
+		});
  63
+		item.addActionListener(new UserData.LogUse("newMenuItem"));
  64
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, modKey));
  65
+		menu.add(item);
  66
+		
  67
+		item = new JMenuItem("Open...");
  68
+		item.addActionListener(IdeWindow.openAction);
  69
+		item.addActionListener(new UserData.LogUse("openMenuItem"));
  70
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, modKey));
  71
+		menu.add(item);
  72
+		recentMenu = new JMenu(applyTitleCase("Open recent"));
  73
+		updateRecentMenu();
  74
+		menu.add(recentMenu);
  75
+		
  76
+		menu.addSeparator();
  77
+		
  78
+		item = new JMenuItem("Close");
  79
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, modKey));
  80
+		if (parent == null) {
  81
+			item.setEnabled(false);
  82
+		}
  83
+		item.addActionListener(new ActionListener() {
  84
+			@Override
  85
+			public void actionPerformed(ActionEvent e) {
  86
+				if (parent != null && parent.promptIfUnsavedAndClose()) {
  87
+					IdeWindow.updateWindowMenu();
  88
+				}
  89
+			}
  90
+		});
  91
+		item.addActionListener(new UserData.LogUse("closeMenuItem"));
  92
+		menu.add(item);
  93
+		
  94
+		item = new JMenuItem("Save");
  95
+		saveItem = item;
  96
+		if (parent == null) {
  97
+			item.setEnabled(false);
  98
+		} else {
  99
+			item.addActionListener(parent.saveAction);
  100
+			item.addActionListener(new UserData.LogUse("saveMenuItem"));
  101
+		}
  102
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, modKey));
  103
+		menu.add(item);
  104
+		
  105
+		item = new JMenuItem("Duplicate");
  106
+		if (parent == null) {
  107
+			item.setEnabled(false);
  108
+		} else {
  109
+			item.addActionListener(new ActionListener(){
  110
+				@Override
  111
+				public void actionPerformed(ActionEvent e) {
  112
+					IdeWindow dupWin = new IdeWindow(parent.editor.getText());
  113
+					dupWin.setVisible(true);
  114
+				}
  115
+			});
  116
+			item.addActionListener(new UserData.LogUse("duplicateMenuItem"));
  117
+		}
  118
+		menu.add(item);
  119
+
  120
+		menu.addSeparator();
  121
+		
  122
+		item = new JMenuItem("Print...");
  123
+		if (parent == null)  {
  124
+			item.setEnabled(false);
  125
+		} else {
  126
+			item.addActionListener(parent.printAction);
  127
+			item.addActionListener(new UserData.LogUse("printMenuItem"));
  128
+		}
  129
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, modKey));
  130
+		menu.add(item);
  131
+		
  132
+		if (!OSX) {
  133
+			menu.addSeparator();
  134
+			item = new JMenuItem(WIN ? "Exit" : "Quit");
  135
+			item.addActionListener(new ActionListener() {
  136
+				@Override
  137
+				public void actionPerformed(ActionEvent e) {
  138
+					new UserData.LogUse("quitMenuItem").actionPerformed(e);
  139
+					for (IdeWindow w : IdeWindow.windows) {
  140
+						w.promptIfUnsavedAndClose();
  141
+					}
  142
+				}
  143
+			});
  144
+			if (!WIN) {
  145
+				item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, modKey));
  146
+			}
  147
+			menu.add(item);
  148
+		}
  149
+		
  150
+		add(menu);
  151
+		
  152
+		/* ******* Edit Menu ******* */
  153
+		menu = new JMenu("Edit");
  154
+		item = new JMenuItem("Undo");
  155
+		undo = item;
  156
+		if (parent == null) {
  157
+			item.setEnabled(false);
  158
+		} else {
  159
+			item.addActionListener(parent.undoAction);
  160
+			item.addActionListener(new UserData.LogUse("undoMenuItem"));
  161
+		}
  162
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, modKey));
  163
+		menu.add(item);
  164
+		
  165
+		item = new JMenuItem("Redo");
  166
+		redo = item;
  167
+		if (parent == null) {
  168
+			item.setEnabled(false);
  169
+		} else {
  170
+			item.addActionListener(parent.redoAction);
  171
+			item.addActionListener(new UserData.LogUse("redoMenuItem"));
  172
+		}
  173
+		if (OSX) {
  174
+			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, modKey | KeyEvent.SHIFT_DOWN_MASK));
  175
+		} else {
  176
+			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, modKey));
  177
+		}
  178
+		menu.add(item);
  179
+		
  180
+		menu.addSeparator();
  181
+		
  182
+		item = new JMenuItem(new DefaultEditorKit.CutAction());
  183
+		item.setText("Cut");
  184
+		item.setEnabled(parent != null);
  185
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, modKey));
  186
+		item.addActionListener(new UserData.LogUse("cutMenuItem"));
  187
+		menu.add(item);
  188
+		
  189
+		item = new JMenuItem(new DefaultEditorKit.CopyAction());
  190
+		item.setText("Copy");
  191
+		item.setEnabled(parent != null);
  192
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, modKey));
  193
+		item.addActionListener(new UserData.LogUse("copyMenuItem"));
  194
+		menu.add(item);
  195
+		
  196
+		item = new JMenuItem(new DefaultEditorKit.PasteAction());
  197
+		item.setText("Paste");
  198
+		item.setEnabled(parent != null);
  199
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, modKey));
  200
+		item.addActionListener(new UserData.LogUse("pasteMenuItem"));
  201
+		menu.add(item);
  202
+		
  203
+		item = new JMenuItem("Delete");
  204
+		if (parent == null) {
  205
+			item.setEnabled(false);
  206
+		} else {
  207
+			item.addActionListener(new ActionListener() {
  208
+				@Override
  209
+				public void actionPerformed(ActionEvent e) {
  210
+					try {
  211
+						int selStart = parent.editor.getSelectionStart();
  212
+						int selEnd = parent.editor.getSelectionEnd();
  213
+						parent.editor.getDocument().remove(selStart, selEnd - selStart);
  214
+					} catch (BadLocationException e1) { }
  215
+				}
  216
+			});
  217
+			item.addActionListener(new UserData.LogUse("deleteMenuItem"));
  218
+		}
  219
+		menu.add(item);
  220
+		
  221
+		item = new JMenuItem(applyTitleCase("Select all"));
  222
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, modKey));
  223
+		if (parent == null) {
  224
+			item.setEnabled(false);
  225
+		} else {
  226
+			item.addActionListener(new ActionListener() {
  227
+				@Override
  228
+				public void actionPerformed(ActionEvent arg0) {
  229
+					parent.editor.selectAll();
  230
+				}
  231
+			});
  232
+			item.addActionListener(new UserData.LogUse("selectAllMenuItem"));
  233
+		}
  234
+		
  235
+		menu.addSeparator();
  236
+		
  237
+		item = new JMenuItem("Find");
  238
+		if (parent == null) {
  239
+			item.setEnabled(false);
  240
+		} else {
  241
+			item.addActionListener(parent.findAction);
  242
+			item.addActionListener(new UserData.LogUse("findMenuItem"));
  243
+		}
  244
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, modKey));
  245
+		menu.add(item);
  246
+		
  247
+		menu.addSeparator();
  248
+		
  249
+		item = new JMenuItem(applyTitleCase("Toggle comment"));
  250
+		item.setEnabled(parent != null);
  251
+		item.addActionListener(new RSyntaxTextAreaEditorKit.ToggleCommentAction());
  252
+		item.addActionListener(new UserData.LogUse("toggleCommentMenuItem"));
  253
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_SEMICOLON, modKey));
  254
+		menu.add(item);
  255
+		item = new JMenuItem(applyTitleCase("Reindent selection"));
  256
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, modKey));
  257
+		if (parent == null) {
  258
+			item.setEnabled(false);
  259
+		} else {
  260
+			item.addActionListener(parent.reindentAction);
  261
+			item.addActionListener(new UserData.LogUse("reindentMenuItem"));
  262
+		}
  263
+		menu.add(item);
  264
+		if (!OSX && !WIN) {
  265
+			menu.addSeparator();
  266
+			item = new JMenuItem("Preferences...");
  267
+			item.addActionListener(prefsAction);
  268
+			item.addActionListener(new UserData.LogUse("preferencesMenuItem"));
  269
+			menu.add(item);
  270
+		}
  271
+		add(menu);
  272
+		/* ******* ACL2 Menu ******* */
  273
+		menu = new JMenu("Tools");
  274
+		item = new JMenuItem("Restart ACL2");
  275
+		item.setEnabled(parent != null);
  276
+		item.addActionListener(new ActionListener() {
  277
+			@Override
  278
+			public void actionPerformed(ActionEvent arg0) {
  279
+				if (parent == null) return;
  280
+				try {
  281
+					parent.acl2.restart();
  282
+					parent.proofBar.resetProgress();
  283
+				} catch (IOException e) {
  284
+					JOptionPane.showMessageDialog(parent, "ACL2 executable not found", "Error",
  285
+							JOptionPane.ERROR_MESSAGE);
  286
+				}
  287
+			}
  288
+		});
  289
+		item.addActionListener(new UserData.LogUse("restartAcl2MenuItem"));
  290
+		menu.add(item);
  291
+		item = new JMenuItem("Interrupt ACL2");
  292
+		if (parent == null) {
  293
+			item.setEnabled(false);
  294
+		} else {
  295
+			item.addActionListener(new ActionListener() {
  296
+				@Override
  297
+				public void actionPerformed(ActionEvent e) {
  298
+					if (parent.acl2 != null && parent.acl2.isAlive()) {
  299
+						parent.acl2.ctrlc();
  300
+					}
  301
+				}
  302
+			});
  303
+			item.addActionListener(new UserData.LogUse("interruptAcl2MenuItem"));
  304
+		}
  305
+		if (OSX) {
  306
+			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK));
  307
+		} else {
  308
+			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_K, modKey));
  309
+		}
  310
+		menu.add(item);
  311
+		menu.addSeparator();
  312
+		item = new JMenuItem(applyTitleCase("Admit next item"));
  313
+		if (OSX) {
  314
+			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,
  315
+					modKey | KeyEvent.ALT_DOWN_MASK));
  316
+		} else {
  317
+			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, modKey));
  318
+		}
  319
+		if (parent == null) {
  320
+			item.setEnabled(false);
  321
+		} else {
  322
+			item.addActionListener(parent.admitNextAction);
  323
+			item.addActionListener(new UserData.LogUse("admitNextMenuItem"));
  324
+		}
  325
+		menu.add(item);
  326
+		item = new JMenuItem(applyTitleCase("Un-admit one item"));
  327
+		if (OSX) {
  328
+			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_UP,
  329
+					modKey | KeyEvent.ALT_DOWN_MASK));
  330
+		} else {
  331
+			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_UP, modKey));
  332
+		}
  333
+		if (parent == null) {
  334
+			item.setEnabled(false);
  335
+		} else {
  336
+			item.addActionListener(parent.undoPrevAction);
  337
+			item.addActionListener(new UserData.LogUse("unAdmitOneMenuItem"));
  338
+		}
  339
+		menu.add(item);
  340
+		menu.addSeparator();
  341
+		item = new JMenuItem(applyTitleCase("Clear REPL scrollback"));
  342
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, modKey));
  343
+		if (parent == null) {
  344
+			item.setEnabled(false);
  345
+		} else {
  346
+			item.addActionListener(parent.clearReplScrollback);
  347
+			item.addActionListener(new UserData.LogUse("clearScrollbackMenuItem"));
  348
+		}
  349
+		menu.add(item);
  350
+		menu.addSeparator();
  351
+		item = new JMenuItem("Build");
  352
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, modKey));
  353
+		if (parent == null) {
  354
+			item.setEnabled(false);
  355
+		} else {
  356
+			item.addActionListener(parent.buildAction);
  357
+			item.addActionListener(new UserData.LogUse("buildMenuItem"));
  358
+		}
  359
+		menu.add(item);
  360
+		menu.addSeparator();
  361
+		item = new JMenuItem(applyTitleCase("Include book..."));
  362
+		if (parent == null) {
  363
+			item.setEnabled(false);
  364
+		} else {
  365
+			item.addActionListener(parent.includeBookAction);
  366
+			item.addActionListener(new UserData.LogUse("includeBookMenuItem"));
  367
+		}
  368
+		menu.add(item);
  369
+		add(menu);
  370
+		if (WIN) {
  371
+			item = new JMenuItem("Options...");
  372
+			item.addActionListener(prefsAction);
  373
+			item.addActionListener(new UserData.LogUse("prefsMenuItem"));
  374
+			menu.addSeparator();
  375
+			menu.add(item);
  376
+		}
  377
+		/* ******* Window Menu (Mac only) ******* */
  378
+		if (OSX) {
  379
+			menu = new JMenu("Window");
  380
+			windowMenu = menu;
  381
+			add(menu);
  382
+			updateWindowMenu();
  383
+		}
  384
+		/* ******* */
  385
+		menu = new JMenu(OSX ? "Help " : "Help");
  386
+		item = new JMenuItem("Index");
  387
+		item = new JMenuItem(applyTitleCase("Quick guide"));
  388
+		item = new JMenuItem("Look up...");
  389
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, modKey | KeyEvent.ALT_DOWN_MASK));
  390
+		if (parent == null) {
  391
+			item.setEnabled(false);
  392
+		} else {
  393
+			item.addActionListener(parent.helpAction);
  394
+			item.addActionListener(new UserData.LogUse("lookUpMenuItem"));
  395
+		}
  396
+		menu.add(item);
  397
+		item = new JMenuItem("Tutorial");
  398
+		if (parent == null) {
  399
+			item.setEnabled(false);
  400
+		} else {
  401
+			item.addActionListener(parent.tutorialAction);
  402
+			item.addActionListener(new UserData.LogUse("tutorialMenuItem"));
  403
+		}
  404
+		menu.add(item);
  405
+		menu.addSeparator();
  406
+		item = new JMenuItem(applyTitleCase("Report a bug"));
  407
+		item.addActionListener(new ActionListener() {
  408
+			@Override
  409
+			public void actionPerformed(ActionEvent e) {
  410
+				try {
  411
+					Desktop.getDesktop().browse(new URI("https://github.com/calebegg/proof-pad/issues/new"));
  412
+				} catch (Exception ex) { }
  413
+			}
  414
+		});
  415
+		item.addActionListener(new UserData.LogUse("reportBugMenuItem"));
  416
+		menu.add(item);
  417
+		if (!OSX) {
  418
+			item = new JMenuItem("About");
  419
+			item.addActionListener(new ActionListener() {
  420
+				@Override
  421
+				public void actionPerformed(ActionEvent e) {
  422
+					new AboutWindow().setVisible(true);
  423
+				}
  424
+			});
  425
+			item.addActionListener(new UserData.LogUse("aboutMenuItem"));
  426
+			menu.add(item);
  427
+		}
  428