2 import ij.plugin.Converter;
3 import ij.plugin.frame.Recorder;
4 import ij.macro.Interpreter;
5 import ij.text.TextWindow;
6 import ij.plugin.frame.PlugInFrame;
11 /** This class consists of static methods used to manage ImageJ's windows. */
12 public class WindowManager {
14 public static boolean checkForDuplicateName;
15 private static Vector imageList = new Vector(); // list of image windows
16 private static Vector nonImageList = new Vector(); // list of non-image windows
17 private static ImageWindow currentWindow; // active image window
18 private static Frame frontWindow;
19 private static Hashtable tempImageTable = new Hashtable();
21 private WindowManager() {
24 /** Makes the image contained in the specified window the active image. */
25 public static void setCurrentWindow(ImageWindow win) {
26 setCurrentWindow(win,false);
29 /** Makes the specified image active. */
30 public static void setCurrentWindow(ImageWindow win,boolean suppressRecording) {
31 if (win==null || win.isClosed() || win.getImagePlus()==null) // deadlock-"wait to lock"
33 //IJ.log("setCurrentWindow: "+win.getImagePlus().getTitle()+" ("+(currentWindow!=null?currentWindow.getImagePlus().getTitle():"null") + ")");
35 tempImageTable.remove(Thread.currentThread());
36 if (win==currentWindow || imageList.size()==0)
38 if (currentWindow!=null) {
39 // free up pixel buffers used by current window
40 ImagePlus imp = currentWindow.getImagePlus();
48 if (!suppressRecording && Recorder.record)
49 Recorder.record("selectWindow", win.getTitle());
53 /** Returns the active ImageWindow. */
54 public static ImageWindow getCurrentWindow() {
55 //if (IJ.debugMode) IJ.write("ImageWindow.getCurrentWindow");
59 static int getCurrentIndex() {
60 return imageList.indexOf(currentWindow);
63 /** Returns a reference to the active image or null if there isn't one. */
64 public static ImagePlus getCurrentImage() {
65 ImagePlus img = (ImagePlus)tempImageTable.get(Thread.currentThread());
66 //String str = (img==null)?" null":"";
68 img = getActiveImage();
69 //if (img!=null) IJ.log("getCurrentImage: "+img.getTitle()+" "+Thread.currentThread().hashCode()+str);
73 /** Makes the specified image temporarily the active
74 image for this thread. Call again with a null
75 argument to revert to the previous active image. */
76 public static void setTempCurrentImage(ImagePlus img) {
77 //IJ.log("setTempImage: "+(img!=null?img.getTitle():"null ")+Thread.currentThread().hashCode());
79 tempImageTable.remove(Thread.currentThread());
81 tempImageTable.put(Thread.currentThread(), img);
84 /** Sets a temporary image for the specified thread. */
85 public static void setTempCurrentImage(Thread thread, ImagePlus img) {
87 throw new RuntimeException("thread==null");
89 tempImageTable.remove(thread);
91 tempImageTable.put(thread, img);
94 /** Returns the active ImagePlus. */
95 private static ImagePlus getActiveImage() {
96 if (currentWindow!=null)
97 return currentWindow.getImagePlus();
98 else if (frontWindow!=null && (frontWindow instanceof ImageWindow))
99 return ((ImageWindow)frontWindow).getImagePlus();
100 else if (imageList.size()>0) {
101 ImageWindow win = (ImageWindow)imageList.elementAt(imageList.size()-1);
102 return win.getImagePlus();
104 return Interpreter.getLastBatchModeImage();
107 /** Returns the number of open image windows. */
108 public static int getWindowCount() {
109 int count = imageList.size();
113 /** Returns the number of open images. */
114 public static int getImageCount() {
115 int count = imageList.size();
116 count += Interpreter.getBatchModeImageCount();
117 if (count==0 && getCurrentImage()!=null)
122 /** Returns the front most window or null. */
123 public static Frame getFrontWindow() {
127 /** Returns a list of the IDs of open images. Returns
128 null if no windows are open. */
129 public synchronized static int[] getIDList() {
130 int nWindows = imageList.size();
131 int[] batchModeImages = Interpreter.getBatchModeImageIDs();
132 int nBatchImages = batchModeImages.length;
133 if ((nWindows+nBatchImages)==0)
135 int[] list = new int[nWindows+nBatchImages];
136 for (int i=0; i<nBatchImages; i++)
137 list[i] = batchModeImages[i];
139 for (int i=nBatchImages; i<nBatchImages+nWindows; i++) {
140 ImageWindow win = (ImageWindow)imageList.elementAt(index++);
141 list[i] = win.getImagePlus().getID();
146 /** Returns an array containing a list of the non-image windows. */
147 public synchronized static Frame[] getNonImageWindows() {
148 Frame[] list = new Frame[nonImageList.size()];
149 nonImageList.copyInto((Frame[])list);
153 /** For IDs less than zero, returns the ImagePlus with the specified ID.
154 Returns null if no open window has a matching ID or no images are open.
155 For IDs greater than zero, returns the Nth ImagePlus. Returns null if
157 public synchronized static ImagePlus getImage(int imageID) {
158 //if (IJ.debugMode) IJ.write("ImageWindow.getImage");
160 imageID = getNthImageID(imageID);
161 if (imageID==0 || getImageCount()==0)
163 ImagePlus imp2 = Interpreter.getBatchModeImage(imageID);
166 ImagePlus imp = null;
167 for (int i=0; i<imageList.size(); i++) {
168 ImageWindow win = (ImageWindow)imageList.elementAt(i);
169 imp2 = win.getImagePlus();
170 if (imageID==imp2.getID()) {
175 imp2 = getCurrentImage();
176 if (imp==null &&imp2!=null && imp2.getID()==imageID)
181 /** Returns the ID of the Nth open image. Returns zero if n<=0
182 or n greater than the number of open image windows. */
183 public synchronized static int getNthImageID(int n) {
185 if (Interpreter.isBatchMode()) {
186 int[] list = getIDList();
192 if (n>imageList.size()) return 0;
193 ImageWindow win = (ImageWindow)imageList.elementAt(n-1);
195 return win.getImagePlus().getID();
202 /** Returns the first image that has the specified title or null if it is not found. */
203 public synchronized static ImagePlus getImage(String title) {
204 int[] wList = getIDList();
205 if (wList==null) return null;
206 for (int i=0; i<wList.length; i++) {
207 ImagePlus imp = getImage(wList[i]);
208 if (imp!=null && imp.getTitle().equals(title))
214 /** Adds the specified window to the Window menu. */
215 public synchronized static void addWindow(Frame win) {
216 //IJ.write("addWindow: "+win.getTitle());
219 else if (win instanceof ImageWindow)
220 addImageWindow((ImageWindow)win);
222 Menus.insertWindowMenuItem(win);
223 nonImageList.addElement(win);
227 private static void addImageWindow(ImageWindow win) {
228 ImagePlus imp = win.getImagePlus();
229 if (imp==null) return;
230 checkForDuplicateName(imp);
231 imageList.addElement(win);
232 Menus.addWindowMenuItem(imp);
233 setCurrentWindow(win,true);
236 static void checkForDuplicateName(ImagePlus imp) {
237 if (checkForDuplicateName) {
238 String name = imp.getTitle();
239 if (isDuplicateName(name))
240 imp.setTitle(getUniqueName(name));
242 checkForDuplicateName = false;
245 static boolean isDuplicateName(String name) {
246 int n = imageList.size();
247 for (int i=0; i<n; i++) {
248 ImageWindow win = (ImageWindow)imageList.elementAt(i);
249 String name2 = win.getImagePlus().getTitle();
250 if (name.equals(name2))
256 /** Returns a unique name by adding, before the extension, -1, -2, etc. as needed. */
257 public static String getUniqueName(String name) {
259 String extension = "";
260 int len = name2.length();
261 int lastDot = name2.lastIndexOf(".");
262 if (lastDot!=-1 && len-lastDot<6 && lastDot!=len-1) {
263 extension = name2.substring(lastDot, len);
264 name2 = name2.substring(0, lastDot);
266 int lastDash = name2.lastIndexOf("-");
267 if (lastDash!=-1 && name2.length()-lastDash<4)
268 name2 = name2.substring(0, lastDash);
269 for (int i=1; i<=99; i++) {
270 String name3 = name2+"-"+ i + extension;
271 //IJ.log(i+" "+name3);
272 if (!isDuplicateName(name3))
278 /** If 'name' is not unique, adds -1, -2, etc. as needed to make it unique. */
279 public static String makeUniqueName(String name) {
280 return isDuplicateName(name)?getUniqueName(name):name;
283 /** Removes the specified window from the Window menu. */
284 public synchronized static void removeWindow(Frame win) {
285 //IJ.write("removeWindow: "+win.getTitle());
286 if (win instanceof ImageWindow)
287 removeImageWindow((ImageWindow)win);
289 int index = nonImageList.indexOf(win);
290 ImageJ ij = IJ.getInstance();
292 //if (ij!=null && !ij.quitting())
293 Menus.removeWindowMenuItem(index);
294 nonImageList.removeElement(win);
300 private static void removeImageWindow(ImageWindow win) {
301 int index = imageList.indexOf(win);
303 return; // not on the window list
304 if (imageList.size()>1) {
305 int newIndex = index-1;
307 newIndex = imageList.size()-1;
308 setCurrentWindow((ImageWindow)imageList.elementAt(newIndex));
310 currentWindow = null;
311 imageList.removeElementAt(index);
312 setTempCurrentImage(null); //???
313 int nonImageCount = nonImageList.size();
316 Menus.removeWindowMenuItem(nonImageCount+index);
321 /** The specified frame becomes the front window, the one returnd by getFrontWindow(). */
322 public static void setWindow(Frame win) {
324 if (Recorder.record && win!=null && win!=frontWindow) {
325 String title = win.getTitle();
326 IJ.log("Set window: "+title+" "+(getFrame(title)!=null?"not null":"null"));
327 if (getFrame(title)!=null && !title.equals("Recorder"))
328 Recorder.record("selectWindow", title);
332 //IJ.log("Set window: "+(win!=null?win.getTitle():"null"));
333 if (IJ.getApplet() != null && win instanceof ImageWindow) {
334 currentWindow = (ImageWindow)win;
335 tempImageTable.remove(Thread.currentThread());
336 ImagePlus current = currentWindow.getImagePlus();
338 current.setActivated();
342 /** Closes all windows. Stops and returns false if any image "save changes" dialog is canceled. */
343 public synchronized static boolean closeAllWindows() {
344 while (imageList.size()>0) {
345 if (!((ImageWindow)imageList.elementAt(0)).close())
349 ImageJ ij = IJ.getInstance();
350 if (ij!=null && ij.quitting() && IJ.getApplet()==null)
352 Frame[] list = getNonImageWindows();
353 for (int i=0; i<list.length; i++) {
354 Frame frame = list[i];
355 if (frame instanceof PlugInFrame)
356 ((PlugInFrame)frame).close();
357 else if (frame instanceof TextWindow)
358 ((TextWindow)frame).close();
360 frame.setVisible(false);
367 /** Activates the next image window on the window list. */
368 public static void putBehind() {
369 if (IJ.debugMode) IJ.log("putBehind");
370 if(imageList.size()<1 || currentWindow==null)
372 int index = imageList.indexOf(currentWindow);
377 if (index<0) index = imageList.size()-1;
378 win = (ImageWindow)imageList.elementAt(index);
379 if (++count==imageList.size()) return;
380 } while (win instanceof HistogramWindow || win instanceof PlotWindow);
381 setCurrentWindow(win);
386 /** Returns the temporary current image for this thread, or null. */
387 public static ImagePlus getTempCurrentImage() {
388 return (ImagePlus)tempImageTable.get(Thread.currentThread());
391 /** Returns the frame with the specified title or null if a frame with that
392 title is not found. */
393 public static Frame getFrame(String title) {
394 for (int i=0; i<nonImageList.size(); i++) {
395 Frame frame = (Frame)nonImageList.elementAt(i);
396 if (title.equals(frame.getTitle()))
399 int[] wList = getIDList();
400 int len = wList!=null?wList.length:0;
401 for (int i=0; i<len; i++) {
402 ImagePlus imp = getImage(wList[i]);
404 if (imp.getTitle().equals(title))
405 return imp.getWindow();
411 /** Activates a window selected from the Window menu. */
412 synchronized static void activateWindow(String menuItemLabel, MenuItem item) {
413 //IJ.write("activateWindow: "+menuItemLabel+" "+item);
414 for (int i=0; i<nonImageList.size(); i++) {
415 Frame win = (Frame)nonImageList.elementAt(i);
416 String title = win.getTitle();
417 if (menuItemLabel.equals(title)) {
419 ((CheckboxMenuItem)item).setState(false);
421 Recorder.record("selectWindow", title);
425 int lastSpace = menuItemLabel.lastIndexOf(' ');
426 if (lastSpace>0) // remove image size (e.g., " 90K")
427 menuItemLabel = menuItemLabel.substring(0, lastSpace);
428 for (int i=0; i<imageList.size(); i++) {
429 ImageWindow win = (ImageWindow)imageList.elementAt(i);
430 String title = win.getImagePlus().getTitle();
431 if (menuItemLabel.equals(title)) {
432 setCurrentWindow(win);
434 int index = imageList.indexOf(win);
435 int n = Menus.window.getItemCount();
436 int start = Menus.WINDOW_MENU_ITEMS+Menus.windowMenuItems2;
437 for (int j=start; j<n; j++) {
438 MenuItem mi = Menus.window.getItem(j);
439 ((CheckboxMenuItem)mi).setState((j-start)==index);
446 /** Repaints all open image windows. */
447 public synchronized static void repaintImageWindows() {
448 int[] list = getIDList();
449 if (list==null) return;
450 for (int i=0; i<list.length; i++) {
451 ImagePlus imp2 = getImage(list[i]);
453 imp2.setTitle(imp2.getTitle()); // update "(G)" flag (global calibration)
454 ImageWindow win = imp2.getWindow();
455 if (win!=null) win.repaint();
460 static void showList() {
462 for (int i=0; i<imageList.size(); i++) {
463 ImageWindow win = (ImageWindow)imageList.elementAt(i);
464 ImagePlus imp = win.getImagePlus();
465 IJ.log(i + " " + imp.getTitle() + (win==currentWindow?"*":""));