File: MacroInstaller.java

package info (click to toggle)
imagej 1.52j-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 5,604 kB
  • sloc: java: 120,017; sh: 279; xml: 161; makefile: 6
file content (536 lines) | stat: -rw-r--r-- 17,152 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
package ij.plugin;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
import ij.*;
import ij.gui.*;
import ij.macro.*;
import ij.text.*;
import ij.util.Tools;
import ij.io.*;
import ij.macro.MacroConstants;
import ij.plugin.frame.*;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                import java.util.*;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            

/** This plugin implements the Plugins/Macros/Install Macros command. It is also used by the Editor
	class to install macros in menus and by the ImageJ class to install macros at startup. */
public class MacroInstaller implements PlugIn, MacroConstants, ActionListener {

	public static final int MAX_SIZE = 28000, MAX_MACROS=100, XINC=10, YINC=18;
	public static final char commandPrefix = '^';
	static final String commandPrefixS = "^";
	static final int MACROS_MENU_COMMANDS = 7; // number of commands in Plugins>Macros submenu
	
	private int[] macroStarts;
	private String[] macroNames;
	private MenuBar mb = new MenuBar();
	private int nMacros;
	private Program pgm;
	private boolean firstEvent = true;
	private String shortcutsInUse;
	private int inUseCount;
	private int nShortcuts;
	private int toolCount;
	private String text;
	private String anonymousName;
	private Menu macrosMenu;
	private int autoRunCount, autoRunAndHideCount;
	private boolean openingStartupMacrosInEditor;
	private boolean installTools = true;
	
	private static String defaultDir, fileName;
	private static MacroInstaller instance, listener;
	private Thread macroToolThread;
	private ArrayList<Menu> subMenus = new ArrayList();
	
	private static Program autoRunPgm;
	private static int autoRunAddress;
	private static String autoRunName;
	private boolean autoRunOnCurrentThread;
	
	public void run(String path) {
		if (path==null || path.equals(""))
			path = showDialog();
		if (path==null) return;
		openingStartupMacrosInEditor = path.indexOf("StartupMacros")!=-1;
		String text = open(path);
		if (text!=null) {
			String functions = Interpreter.getAdditionalFunctions();
			if (functions!=null) {
				if (!(text.endsWith("\n") || functions.startsWith("\n")))
					text = text + "\n" + functions;
				else
					text = text + functions;
			}
			install(text);
		}
	}
			
	void install() {
		subMenus.clear();
		if (text!=null) {
			Tokenizer tok = new Tokenizer();
			pgm = tok.tokenize(text);
		}
		if (macrosMenu!=null)
			IJ.showStatus("");
		int[] code = pgm.getCode();
		Symbol[] symbolTable = pgm.getSymbolTable();
		int count=0, token, nextToken, address;
		String name;
		Symbol symbol;
		shortcutsInUse = null;
		inUseCount = 0;
		nShortcuts = 0;
		toolCount = 0;
		macroStarts = new int[MAX_MACROS];
		macroNames = new String[MAX_MACROS];
		boolean isPluginsMacrosMenu = false;
		if (macrosMenu!=null) {
			int itemCount = macrosMenu.getItemCount();
			isPluginsMacrosMenu = macrosMenu==Menus.getMacrosMenu();
			int baseCount =isPluginsMacrosMenu?MACROS_MENU_COMMANDS:Editor.MACROS_MENU_ITEMS;
			if (itemCount>baseCount) {
				for (int i=itemCount-1; i>=baseCount; i--)
					macrosMenu.remove(i);
			}
		}
		if (pgm.hasVars() && pgm.macroCount()>0 && pgm.getGlobals()==null)
			new Interpreter().saveGlobals(pgm);
		ArrayList tools = new ArrayList();
		for (int i=0; i<code.length; i++) {
			token = code[i]&TOK_MASK;
			if (token==MACRO) {
				nextToken = code[i+1]&TOK_MASK;
				if (nextToken==STRING_CONSTANT) {
					if (count==MAX_MACROS) {
						if (isPluginsMacrosMenu)
							IJ.error("Macro Installer", "Macro sets are limited to "+MAX_MACROS+" macros.");
						break;
					}
					address = code[i+1]>>TOK_SHIFT;
					symbol = symbolTable[address];
					name = symbol.str;
					macroStarts[count] = i + 2;
					macroNames[count] = name;
					if (name.indexOf('-')!=-1 && (name.indexOf("Tool")!=-1||name.indexOf("tool")!=-1)) {
						tools.add(name);
						toolCount++;
					} else if (name.startsWith("AutoRun")) {
						if (autoRunCount==0 && !openingStartupMacrosInEditor && !IJ.isMacro()) {
							if (autoRunOnCurrentThread) { //autoRun() method will run later
								autoRunPgm = pgm;
								autoRunAddress = macroStarts[count];
								autoRunName = name;
							} else
								new MacroRunner(pgm, macroStarts[count], name, (String)null); // run on separate thread
							if (name.equals("AutoRunAndHide"))
								autoRunAndHideCount++;
						}
						autoRunCount++;
						count--;
					} else if  (name.equals("Popup Menu"))
						installPopupMenu(name, pgm);
					else if (!name.endsWith("Tool Selected")) { 
						if (macrosMenu!=null) {
							addShortcut(name);
							int pos = name.indexOf(">");
							boolean inSubMenu = name.startsWith("<") && (pos>1);
							if (inSubMenu) {
								Menu parent = macrosMenu;
								Menu subMenu = null;
								String parentStr = name.substring(1, pos).trim();
								String childStr = name.substring(pos + 1).trim();
								MenuItem mnuItem = new MenuItem();
								mnuItem.setActionCommand(name);
								mnuItem.setLabel(childStr);
								for (int jj = 0; jj < subMenus.size(); jj++) {
									String aName = subMenus.get(jj).getName();
									if (aName.equals(parentStr))
										subMenu = subMenus.get(jj);
								}
								if (subMenu==null) {
									subMenu = new Menu(parentStr);
									subMenu.setName(parentStr);
									subMenu.addActionListener(this);
									subMenus.add(subMenu);
									parent.add(subMenu);
								}
								subMenu.add(mnuItem);
							} else
								macrosMenu.add(new MenuItem(name));
						}
					}
					//IJ.log(count+" "+name+" "+macroStarts[count]);
					count++;
				}					
			} else if (token==EOF)
				break;
		}
		nMacros = count;
		if (toolCount>0 && (isPluginsMacrosMenu||macrosMenu==null) && installTools) {
			Toolbar tb = Toolbar.getInstance();
			if (toolCount==1) 
				tb.addMacroTool((String)tools.get(0), this);
			else {
				for (int i=0; i<tools.size(); i++) {
					String toolName = (String)tools.get(i);
					if (toolName.startsWith("Abort Macro or Plugin") && toolCount>6)
						toolName = "Unused "+toolName;
					tb.addMacroTool(toolName, this, i);
				}
			}
			if (toolCount>1 && Toolbar.getToolId()>=Toolbar.CUSTOM1)
				tb.setTool(Toolbar.RECTANGLE);
			tb.repaint();
		}
		if (macrosMenu!=null)
			this.instance = this;
		if (shortcutsInUse!=null && text!=null)
			IJ.showMessage("Install Macros", (inUseCount==1?"This keyboard shortcut is":"These keyboard shortcuts are")
			+ " already in use:"+shortcutsInUse);
		if (nMacros==0 && fileName!=null) {
			if (text==null||text.length()==0)
				return;
			int dotIndex = fileName.lastIndexOf('.');
			if (dotIndex>0)
				anonymousName = fileName.substring(0, dotIndex);
			else
				anonymousName =fileName;
			if (macrosMenu!=null)
				macrosMenu.add(new MenuItem(anonymousName));
			macroNames[0] = anonymousName;
			nMacros = 1;
		}
		String word = nMacros==1?" macro":" macros";
		if (isPluginsMacrosMenu)
			IJ.showStatus(nMacros + word + " installed");
	}
	
	public int install(String text) {
		if (text==null && pgm==null)
			return 0;
		this.text = text;
		macrosMenu = Menus.getMacrosMenu();
		if (listener!=null)
			macrosMenu.removeActionListener(listener);
		macrosMenu.addActionListener(this);
		listener = this;
		install();
		return nShortcuts;
	}
	
	public int install(String text, Menu menu) {
		this.text = text;
		macrosMenu = menu;
		install();
		int count = nShortcuts+toolCount;
		if (count==0 && nMacros>1)
			count = nMacros;
		return count;
	}

	public void installFile(String path) {
		String text = open(path);
		if (text==null) return;
		boolean isStartupMacros = path.contains("StartupMacros");
		if (isStartupMacros && !Toolbar.installStartupMacrosTools())
			installTools = false;
		//IJ.log("installFile: "+path+" "+isStartupMacros+" "+installTools);
		install(text);
		installTools = true;
		if (isStartupMacros) {
			Toolbar tb = Toolbar.getInstance();
			if (tb!=null)
				tb.installStartupTools();
		}
	}

	public void installTool(String path) {
		String text = open(path);
		if (text!=null)
			installSingleTool(text);
	}

	public void installLibrary(String path) {
			String text = open(path);
			if (text!=null)
				Interpreter.setAdditionalFunctions(text);
	}

	 /** Installs a macro set contained in ij.jar. */
	public void installFromIJJar(String path) {
		String text = openFromIJJar(path);
		if (text==null) return;
		if (path.endsWith("StartupMacros.txt")) {
			if (Toolbar.installStartupMacrosTools())
				install(text);
			Toolbar tb = Toolbar.getInstance();
			if (tb!=null)
				tb.installStartupTools();
		} else if (path.contains("Tools"))
			install(text);
		else
			installSingleTool(text);
	}

	public void installSingleTool(String text) {
		this.text = text;
		macrosMenu = null;
		install();
	}

	void installPopupMenu(String name, Program pgm) {
        Hashtable h = pgm.getMenus();
        if (h==null) return;
        String[] commands = (String[])h.get(name);
        if (commands==null) return;
        PopupMenu popup = Menus.getPopupMenu();
        if (popup==null) return;
		popup.removeAll();
        for (int i=0; i<commands.length; i++) {
			if (commands[i].equals("-"))
				popup.addSeparator();
			else {
				MenuItem mi = new MenuItem(commands[i]);
				mi.addActionListener(this);
				popup.add(mi);
			}
        }
	}

	void removeShortcuts() {
		Menus.getMacroShortcuts().clear();
		Hashtable shortcuts = Menus.getShortcuts();
		for (Enumeration en=shortcuts.keys(); en.hasMoreElements();) {
			Integer key = (Integer)en.nextElement();
			String value = (String)shortcuts.get(key);
			if (value.charAt(0)==commandPrefix)
				shortcuts.remove(key);
		}
	}

	void addShortcut(String name) {
		int index1 = name.indexOf('[');
		if (index1==-1)
			return;
		int index2 = name.lastIndexOf(']');
		if (index2<=(index1+1))
			return;
		String shortcut = name.substring(index1+1, index2);
		int len = shortcut.length();
		if (len>1)
			shortcut = shortcut.toUpperCase(Locale.US);;
		if (len>3 || (len>1&&shortcut.charAt(0)!='F'&&shortcut.charAt(0)!='N'))
			return;
		int code = Menus.convertShortcutToCode(shortcut);
		if (code==0)
			return;
		if (nShortcuts==0)
			removeShortcuts();
		// One character shortcuts go in a separate hash table to
		// avoid conflicts with ImageJ menu shortcuts.
		if (len==1 || shortcut.equals("N+") || shortcut.equals("N-") ) {
			Hashtable macroShortcuts = Menus.getMacroShortcuts();
			macroShortcuts.put(new Integer(code), commandPrefix+name);
			nShortcuts++;
			return;
		}
		Hashtable shortcuts = Menus.getShortcuts();
		if (shortcuts.get(new Integer(code))!=null) {
			if (shortcutsInUse==null)
				shortcutsInUse = "\n \n";
			shortcutsInUse += "	  " + name + "\n";
			inUseCount++;
			return;
		}
		shortcuts.put(new Integer(code), commandPrefix+name);
		nShortcuts++;
		//IJ.log("addShortcut3: "+name+"	  "+shortcut+"	  "+code);
	}
	
	 String showDialog() {
		if (defaultDir==null) defaultDir = Menus.getMacrosPath();
		OpenDialog od = new OpenDialog("Install Macros", defaultDir, fileName);
		String name = od.getFileName();
		if (name==null) return null;
		String dir = od.getDirectory();
		if (!(name.endsWith(".txt")||name.endsWith(".ijm"))) {
			IJ.showMessage("Macro Installer", "File name must end with \".txt\" or \".ijm\" .");
			return null;
		}
		fileName = name;
		defaultDir = dir;
		return dir+name;
	}

	String open(String path) {
		if (path==null) return null;
		try {
			StringBuffer sb = new StringBuffer(5000);
			BufferedReader r = new BufferedReader(new FileReader(path));
			while (true) {
				String s=r.readLine();
				if (s==null)
					break;
				else
					sb.append(s+"\n");
			}
			r.close();
			return new String(sb);
		}
		catch (Exception e) {
			IJ.error(e.getMessage());
			return null;
		}
	}
	 
	 /** Returns a text file contained in ij.jar. */
	 public String openFromIJJar(String path) {
		String text = null;
		  try {
			InputStream is = this.getClass().getResourceAsStream(path);
			//IJ.log(is+"	"+path);
			if (is==null) return null;
				InputStreamReader isr = new InputStreamReader(is);
				StringBuffer sb = new StringBuffer();
				char [] b = new char [8192];
				int n;
				while ((n = isr.read(b)) > 0)
					 sb.append(b,0, n);
				text = sb.toString();
		  }
		  catch (IOException e) {}
		  return text;
	}
	
	public boolean runMacroTool(String name) {
		for (int i=0; i<nMacros; i++) {
			if (macroNames[i].startsWith(name)) {
				if (macroToolThread!=null && macroToolThread.getName().indexOf(name)!=-1 && macroToolThread.isAlive())
					return false; // do nothing if this tool is already running
				MacroRunner mw = new MacroRunner(pgm, macroStarts[i], name, (String)null);
				macroToolThread = mw.getThread();
				//IJ.log("runMacroTool: "+macroToolThread);
				return true;
			}
		}
		return false;
	}
	
	public boolean runMenuTool(String name, String command) {
		for (int i=0; i<nMacros; i++) {
			if (macroNames[i].startsWith(name)) {
				Recorder.recordInMacros = true;
				new MacroRunner(pgm, macroStarts[i], name, command);
				return true;
			}
		}
		return false;
	}

	/** Runs a command in the Plugins/Macros submenu on the current thread. */
	public static boolean runMacroCommand(String name) {
		if (instance==null)
			return false;
		if (name.startsWith(commandPrefixS))
			name = name.substring(1);
		for (int i=0; i<instance.nMacros; i++) {
			if (name.equals(instance.macroNames[i])) {
				MacroRunner mm = new MacroRunner();
				mm.run(instance.pgm, instance.macroStarts[i], name);
				return true;
			}
		}
		return false;
	}
	
	public static void runMacroShortcut(String name) {
		if (instance==null)
			return;
		if (name.startsWith(commandPrefixS))
			name = name.substring(1);
		for (int i=0; i<instance.nMacros; i++) {
			if (name.equals(instance.macroNames[i])) {
				(new MacroRunner()).runShortcut(instance.pgm, instance.macroStarts[i], name);
				return;
			}
		}
	}

	public void runMacro(String name) {
		runMacro(name, null);
	}

	public void runMacro(String name, Editor editor) {
		if (anonymousName!=null && name.equals(anonymousName)) {
			ImageJ.setCommandName(name);
			new MacroRunner(pgm, 0, anonymousName, editor);
			return;
		}
		for (int i=0; i<nMacros; i++)
			if (name.equals(macroNames[i])) {
				ImageJ.setCommandName(name);
				Interpreter.abort(); // abort any currently running macro
				new MacroRunner(pgm, macroStarts[i], name, editor);
				return;
			}
	}
		
	public int getMacroCount() {
		return nMacros;
	}
    
    public Program getProgram() {
		return pgm;
	}

		
	/** Returns true if an "AutoRunAndHide" macro was run/installed. */
	public boolean isAutoRunAndHide() {
		return autoRunAndHideCount>0;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
		openingStartupMacrosInEditor = fileName.startsWith("StartupMacros");
	}

	public static String getFileName() {
		return fileName;
	}
	
	public void actionPerformed(ActionEvent evt) {
		String cmd = evt.getActionCommand();
		ImageJ.setCommandName(cmd);
		MenuItem item = (MenuItem)evt.getSource();
		MenuContainer parent = item.getParent();
		if (parent instanceof PopupMenu) {
			for (int i=0; i<nMacros; i++) {
				if (macroNames[i].equals("Popup Menu")) {
					new MacroRunner(pgm, macroStarts[i], "Popup Menu", cmd);
					return;
				}
			}
		}
		runMacro(cmd);
	}
	
	/** Installs startup macros and runs AutoRun macro on current thread. */
	public void installStartupMacros(String path) {
		autoRunOnCurrentThread = true;
		installFile(path);
		autoRunOnCurrentThread = false;
	}
	
	/** Runs the StartupMacros AutoRun macro on the current thread. */
	public static void autoRun() {
		if (autoRunPgm!=null)
			(new MacroRunner()).run(autoRunPgm, autoRunAddress, autoRunName);
		autoRunPgm = null;
	}

}