KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > antlr > xjlib > appkit > app > XJApplication


1 /*
2
3 [The "BSD licence"]
4 Copyright (c) 2005 Jean Bovet
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. The name of the author may not be used to endorse or promote products
17 derived from this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 */

31
32 package org.antlr.xjlib.appkit.app;
33
34 import org.antlr.xjlib.appkit.document.XJData;
35 import org.antlr.xjlib.appkit.document.XJDocument;
36 import org.antlr.xjlib.appkit.document.XJDocumentType;
37 import org.antlr.xjlib.appkit.frame.XJFrame;
38 import org.antlr.xjlib.appkit.frame.XJFrameDelegate;
39 import org.antlr.xjlib.appkit.frame.XJPanel;
40 import org.antlr.xjlib.appkit.frame.XJWindow;
41 import org.antlr.xjlib.appkit.menu.XJMainMenuBar;
42 import org.antlr.xjlib.appkit.utils.XJAlert;
43 import org.antlr.xjlib.appkit.utils.XJAlertInput;
44 import org.antlr.xjlib.appkit.utils.XJFileChooser;
45 import org.antlr.xjlib.appkit.utils.XJLocalizable;
46 import org.antlr.xjlib.foundation.XJObject;
47 import org.antlr.xjlib.foundation.XJSystem;
48 import org.antlr.xjlib.foundation.timer.XJScheduledTimer;
49 import org.antlr.xjlib.foundation.timer.XJScheduledTimerDelegate;
50
51 import javax.swing.*;
52 import java.awt.*;
53 import java.io.File JavaDoc;
54 import java.util.ArrayList JavaDoc;
55 import java.util.Iterator JavaDoc;
56 import java.util.List JavaDoc;
57 import java.util.TimerTask JavaDoc;
58
59 public class XJApplication extends XJObject implements XJApplicationInterface, XJFrameDelegate {
60
61     public static final boolean YES = true;
62     public static final boolean NO = false;
63
64     public static final String JavaDoc XJ_PREFS_RECENT_FILES = "XJ_PREFS_RECENT_FILES";
65
66     protected static XJApplicationInterface shared = null;
67     protected static XJApplicationDelegate delegate = null;
68
69     protected static List JavaDoc<XJScheduledTimer> scheduledTimers = new ArrayList JavaDoc<XJScheduledTimer>();
70     protected static final long SCHEDULED_TIMER_MINUTES = 1;
71
72     protected static List JavaDoc<XJDocument> documents = new ArrayList JavaDoc<XJDocument>();
73     protected static List JavaDoc<XJWindow> windows = new ArrayList JavaDoc<XJWindow>();
74
75     public static final int MAX_RECENT_FILES = 10;
76     protected static List JavaDoc<String JavaDoc> recentFiles = null;
77
78     protected static int documentAbsoluteCount = 0;
79     protected static int documentAbsPositionCount = 0;
80     protected static final int DOCUMENT_OFFSET_PIXELS = 20;
81
82     protected static List JavaDoc<XJDocumentType> documentType = new ArrayList JavaDoc<XJDocumentType>();
83     protected static String JavaDoc propertiesPath = "";
84
85     protected static boolean startingUp = true;
86     protected static String JavaDoc[] launchArguments = null;
87     protected static List JavaDoc<String JavaDoc> documentsToOpenAtStartup = new ArrayList JavaDoc<String JavaDoc>();
88
89     protected static String JavaDoc appName = "";
90
91     protected XJPreferences userPrefs = null;
92
93     protected XJFrame about = null;
94     protected XJPanel prefs = null;
95
96     protected static XJScheduledTimerDelegate autoSaveTimer = null;
97     private static boolean useDesktopMode;
98
99     public static synchronized void setShared(XJApplicationInterface shared) {
100         XJApplication.shared = shared;
101     }
102
103     public static synchronized XJApplicationInterface shared() {
104         if(shared == null) {
105             if(XJSystem.isMacOS()) {
106                 try {
107                     shared = (XJApplication)Class.forName("org.antlr.xjlib.appkit.app.MacOS.XJApplicationMacOS").newInstance();
108                 } catch (Exception JavaDoc e) {
109                     e.printStackTrace();
110                     System.err.println("XJApplication: cannot instanciate the MacOS application ("+e+")");
111                 }
112             }
113
114             if(shared == null)
115                 shared = new XJApplication();
116
117             ((XJApplication)shared).startup();
118         }
119         return shared;
120     }
121
122     public static String JavaDoc getAppVersionShort() {
123         return delegate.appVersionShort();
124     }
125
126     public static String JavaDoc getAppVersionLong() {
127         return delegate.appVersionLong();
128     }
129
130     public static XJApplicationDelegate getAppDelegate() {
131         return delegate;
132     }
133
134     public static Container getActiveContainer() {
135         Frame[] frame = Frame.getFrames();
136         for (Frame f : frame) {
137             if (f.isActive() && f.isVisible()) {
138                 if (f.getSize().width != 0 && f.getSize().height != 0)
139                     return f;
140             }
141         }
142         return null;
143     }
144
145     public XJApplication() {
146         userPrefs = new XJPreferences(getPreferencesClass());
147         recentFiles = userPrefs.getList(XJ_PREFS_RECENT_FILES);
148         if(recentFiles == null)
149             recentFiles = new ArrayList JavaDoc<String JavaDoc>();
150         XJMainMenuBar.refreshAllRecentFilesMenu();
151     }
152
153     public static void run(XJApplicationDelegate delegate, String JavaDoc[] args, String JavaDoc applicationName) {
154         XJApplication.appName = applicationName;
155
156         if(XJSystem.isMacOS()) {
157             System.setProperty("com.apple.mrj.application.apple.menu.about.name", applicationName);
158         }
159
160         run(delegate, args);
161     }
162
163     public static void run(XJApplicationDelegate delegate, String JavaDoc[] args) {
164         setDelegate(delegate);
165         launchArguments = args;
166         useDesktopMode = XJApplication.delegate.useDesktopMode();
167
168         SwingUtilities.invokeLater(new Runnable JavaDoc() {
169             public void run() {
170                 XJApplication.startingUp = false;
171                 XJApplication.delegate.appDidLaunch(launchArguments, documentsToOpenAtStartup);
172                 documentsToOpenAtStartup.clear();
173                 new java.util.Timer JavaDoc().schedule(new ScheduledTimer(), 1000, 1000*60*SCHEDULED_TIMER_MINUTES);
174             }
175         });
176     }
177
178     protected void startup() {
179         if(hasPreferencesMenuItem())
180             addPreferencesMenuItem();
181         else
182             removePreferencesMenuItem();
183     }
184
185     protected void shutdown() {
186         userPrefs.setList(XJ_PREFS_RECENT_FILES, recentFiles);
187         System.exit(0);
188     }
189
190     public static void setDelegate(XJApplicationDelegate delegate) {
191         XJApplication.delegate = delegate;
192     }
193
194     public static void addScheduledTimer(XJScheduledTimerDelegate delegate, long minutes, boolean scheduleAtStartup) {
195         scheduledTimers.add(new XJScheduledTimer(delegate, minutes, scheduleAtStartup));
196     }
197
198     public static void removeScheduledTimer(XJScheduledTimerDelegate delegate) {
199         for(int index = scheduledTimers.size()-1; index >= 0; index--) {
200             XJScheduledTimer timer = scheduledTimers.get(index);
201             if(timer.getDelegate() == delegate) {
202                 scheduledTimers.remove(timer);
203             }
204         }
205     }
206
207     protected static class ScheduledTimer extends TimerTask JavaDoc {
208
209         protected boolean startup = true;
210
211         public void run() {
212             for (XJScheduledTimer timer : scheduledTimers) {
213                 timer.fire(startup, SCHEDULED_TIMER_MINUTES);
214             }
215
216             startup = false;
217         }
218     }
219
220     public static void setPropertiesPath(String JavaDoc path) {
221         propertiesPath = path;
222     }
223
224     public static String JavaDoc getPropertiesPath() {
225         return propertiesPath;
226     }
227
228     public String JavaDoc getApplicationName() {
229         if(delegate != null) {
230             return delegate.appName();
231         } else {
232             return "";
233         }
234     }
235
236     public XJPreferences getPreferences() {
237         return userPrefs;
238     }
239
240     public void displayAbout() {
241         boolean awake = (about == null);
242
243         if(about == null)
244             about = delegate.appInstanciateAboutPanel();
245
246         if(about == null)
247             about = new XJAboutBox();
248
249         if(awake) {
250             about.setDelegate(this);
251             about.awake();
252         }
253         about.setVisible(true);
254     }
255
256     public void displayPrefs() {
257         if(prefs == null) {
258             try {
259                 prefs = (XJPanel)delegate.appPreferencesPanelClass().newInstance();
260                 prefs.setDelegate(this);
261                 prefs.awake();
262             } catch (Exception JavaDoc e) {
263                 e.printStackTrace();
264                 System.err.println("Cannot instanciate the Preferences panel: "+e);
265                 return;
266             }
267             prefs.center();
268         }
269         prefs.setVisible(true);
270     }
271
272     public void displayHelp() {
273         delegate.appShowHelp();
274     }
275
276     public void frameDidClose(XJFrame frame) {
277         if(frame == prefs)
278             prefs = null;
279         if(frame == about)
280             about = null;
281     }
282
283     public void addRecentFile(String JavaDoc file) {
284         if(file == null) return;
285         
286         if(recentFiles.contains(file))
287             recentFiles.remove(file);
288
289         if(recentFiles.size() > MAX_RECENT_FILES)
290             recentFiles.remove(recentFiles.size()-1);
291
292         recentFiles.add(0, file);
293         XJMainMenuBar.refreshAllRecentFilesMenu();
294     }
295
296     public void removeRecentFile(String JavaDoc file) {
297         recentFiles.remove(file);
298         XJMainMenuBar.refreshAllRecentFilesMenu();
299     }
300
301     public void clearRecentFiles() {
302         recentFiles.clear();
303         XJMainMenuBar.refreshAllRecentFilesMenu();
304     }
305
306     public List JavaDoc recentFiles() {
307         return recentFiles;
308     }
309
310     // *** Menu
311

312     protected void addPreferencesMenuItem() {
313     }
314
315     protected void removePreferencesMenuItem() {
316     }
317
318     public void refreshMainMenuBar() {
319         XJMainMenuBar.refreshAllMenuBars();
320     }
321
322     // *** XJDocument
323

324     public static void addDocumentType(Class JavaDoc documentClass, Class JavaDoc windowClass, Class JavaDoc dataClass, String JavaDoc ext, String JavaDoc description) {
325         documentType.add(new XJDocumentType(documentClass, windowClass, dataClass, ext, description));
326     }
327
328     public static void addDocumentType(Class JavaDoc documentClass, Class JavaDoc windowClass, Class JavaDoc dataClass, String JavaDoc[] ext, String JavaDoc description) {
329         documentType.add(new XJDocumentType(documentClass, windowClass, dataClass, ext, description));
330     }
331
332     public XJDocumentType getDocumentTypeForPath(String JavaDoc path) {
333         for (XJDocumentType doc : documentType) {
334             int index = path.indexOf(".");
335             if (index != -1 && doc.getExtensions().contains(path.substring(index + 1)))
336             {
337                 return doc;
338             }
339         }
340         return null;
341     }
342
343     public XJDocumentType getDocumentTypeForDataClass(Class JavaDoc dc) {
344         for (XJDocumentType doc : documentType) {
345             if (doc.getDataClass().equals(dc))
346                 return doc;
347         }
348         return null;
349     }
350
351     public List JavaDoc getDocumentExtensions() {
352         List JavaDoc<List JavaDoc> ext = new ArrayList JavaDoc<List JavaDoc>();
353         for (XJDocumentType doc : documentType) {
354             ext.add(doc.getExtensions());
355         }
356         return ext;
357     }
358
359     public List JavaDoc<String JavaDoc> getDocumentDescriptions() {
360         List JavaDoc<String JavaDoc> descr = new ArrayList JavaDoc<String JavaDoc>();
361         for (XJDocumentType doc : documentType) {
362             descr.add(doc.getDescriptionString());
363         }
364         return descr;
365     }
366
367     public List JavaDoc<XJDocument> getDocuments() {
368         return documents;
369     }
370
371     public XJDocumentType askForDocumentType() {
372         if(documentType.size() == 1)
373             return documentType.get(0);
374
375         int index = XJAlertInput.showInputDialog(null, XJLocalizable.getXJString("AppNewDocTitle"),
376                 XJLocalizable.getXJString("AppNewDocMessage"), getDocumentDescriptions(), getDocumentDescriptions().get(0));
377         if(index == -1)
378             return null;
379         else
380             return documentType.get(index);
381     }
382
383     public XJDocument newDocument(boolean visible, XJDocumentType docType) {
384         if(documentType.size() == 0) {
385             XJAlert.display(null, XJLocalizable.getXJString("AppNewDocErrTitle"), XJLocalizable.getXJString("AppNewDocErrMessage"));
386             return null;
387         }
388
389         if(docType == null) {
390             docType = askForDocumentType();
391             if(docType == null)
392                 return null;
393         }
394
395         XJDocument document;
396         try {
397             document = (XJDocument)docType.getDocumentClass().newInstance();
398             document.setDocumentData((XJData)docType.getDataClass().newInstance());
399
400             XJWindow window = (XJWindow)docType.getWindowClass().newInstance();
401             document.setWindow(window);
402             window.awake();
403
404             document.awake();
405             document.setDocumentFileType(docType.getExtensions(), docType.getDescriptionString());
406
407             if(supportsPersistence())
408                 document.setTitle(XJLocalizable.getXJString("AppUntitled")+" "+documentAbsoluteCount);
409             else
410                 document.setTitle(documentAbsoluteCount > 0 ?appName+" "+documentAbsoluteCount:appName);
411
412             if(!window.isMaximized() && useDesktopMode()) {
413                 documentAbsoluteCount++;
414
415                 document.getWindow().offsetPosition(documentAbsPositionCount*DOCUMENT_OFFSET_PIXELS,
416                         documentAbsPositionCount*DOCUMENT_OFFSET_PIXELS);
417
418                 if(document.getWindow().isCompletelyOnScreen())
419                     documentAbsPositionCount++;
420                 else
421                     documentAbsPositionCount = 0;
422             }
423         } catch(Exception JavaDoc e) {
424             e.printStackTrace();
425             XJAlert.display(null, XJLocalizable.getXJString("AppNewDocError"), e.toString());
426             return null;
427         }
428
429         if(visible)
430             document.showWindow();
431
432         return document;
433     }
434
435     public XJDocument newDocumentOfData(Class JavaDoc dataClass) {
436         return newDocument(true, getDocumentTypeForDataClass(dataClass));
437     }
438
439     public XJDocument newDocument() {
440         return newDocument(true, null);
441     }
442
443     public boolean openDocuments(List JavaDoc<String JavaDoc> files) {
444         boolean success = true;
445         for(String JavaDoc file : files) {
446             if(!openDocument(file)) success = false;
447         }
448         return success;
449     }
450
451     public boolean openDocument(String JavaDoc file) {
452         if(file == null)
453             return false;
454
455         // FIX AW-63:
456
// On Mac OS X, openDocument might be called during startup which causes
457
// some issue because the application didn't have time to register its document
458
// class type. Accumulate the documents in a list that will be provided to the
459
// application in the didRun method (see above).
460
if(startingUp) {
461             documentsToOpenAtStartup.add(file);
462             return true;
463         }
464
465         XJDocument document = getDocumentForPath(file);
466         if(document != null) {
467             document.getWindow().bringToFront();
468             return true;
469         } else {
470             document = newDocument(false, getDocumentTypeForPath(file));
471             if(document == null)
472                 return false;
473             else if(document.performLoad(file)) {
474                 addRecentFile(file);
475                 document.showWindow();
476                 closeFirstCreatedWindowIfNonDirty();
477                 return true;
478             } else {
479                 document.performClose(true);
480                 return false;
481             }
482         }
483     }
484
485     public boolean openDocument() {
486         return XJFileChooser.shared().displayOpenDialog(null, getDocumentExtensions(), getDocumentDescriptions(), false)
487                 && openDocument(XJFileChooser.shared().getSelectedFilePath());
488
489     }
490
491     public boolean openLastUsedDocument() {
492         if(recentFiles.isEmpty())
493             return false;
494
495         String JavaDoc file = recentFiles.get(0);
496         while(!new File JavaDoc(file).exists()) {
497             recentFiles.remove(0);
498             if(recentFiles.isEmpty())
499                 return false;
500
501             file = recentFiles.get(0);
502         }
503
504         if(openDocument(file))
505             return true;
506
507         removeRecentFile(file);
508         return false;
509     }
510
511     public void addDocument(XJDocument document) {
512         documents.add(document);
513     }
514
515     public void removeDocument(XJDocument document) {
516         documents.remove(document);
517     }
518
519     public void closeFirstCreatedWindowIfNonDirty() {
520         for (XJDocument document : documents) {
521             if (document.isFirstDocument() && !document.isDirty() && document.getDocumentPath() == null)
522             {
523                 document.performClose();
524                 break;
525             }
526         }
527     }
528
529     public XJDocument getActiveDocument() {
530         for (XJDocument document : documents) {
531             // Note:
532
// A document may have no window associated. For example, ANTLRWorks projects
533
// contains a document for each file: these documents don't have a window associated because
534
// they are part of the global project's window (which is referenced by
535
// the project's document itself)
536
if (document.getWindow() != null && document.getWindow().isActive())
537                 return document;
538         }
539         return null;
540     }
541
542     public XJDocument getDocumentForPath(String JavaDoc path) {
543         for (XJDocument document : documents) {
544             String JavaDoc docPath = document.getDocumentPath();
545             if (docPath != null && docPath.equals(path))
546                 return document;
547         }
548         return null;
549     }
550
551     public XJWindow getActiveWindow() {
552         for (XJWindow window : windows) {
553             if (window.isActive())
554                 return window;
555         }
556         return null;
557     }
558
559     // ** XJWindow
560

561     public void addWindow(XJWindow window) {
562         windows.add(window);
563     }
564
565     public int getNumberOfNonAuxiliaryWindows() {
566         int count = 0;
567         for (XJWindow window : windows) {
568             if (!window.isAuxiliaryWindow())
569                 count++;
570         }
571         return count;
572     }
573
574     public void removeWindow(XJWindow window) {
575         windows.remove(window);
576         refreshMainMenuBar();
577         if(getNumberOfNonAuxiliaryWindows() == 0 && !startingUp) {
578             if((!XJSystem.isMacOS() && !useDesktopMode()) || shouldQuitAfterLastWindowClosed()) {
579                 // Invoke the application quit method later in time to allow
580
// the code closing the window to complete its execution.
581
// For example, to store the window size and position before
582
// the application is exited.
583
SwingUtilities.invokeLater(new Runnable JavaDoc() {
584                     public void run() {
585                         performQuit();
586                     }
587                 });
588             }
589         }
590     }
591
592     public List JavaDoc<XJWindow> getWindows() {
593         return windows;
594     }
595
596     public List JavaDoc<XJWindow> getWindowsInWindowMenu() {
597         List JavaDoc<XJWindow> wim = new ArrayList JavaDoc<XJWindow>();
598         for(XJWindow w : windows) {
599             if(w.shouldAppearsInWindowMenu()) {
600                 wim.add(w);
601             }
602         }
603         return wim;
604     }
605
606     // *** Auto-save feature
607

608     public static void setAutoSave(boolean enabled, int delayInMinutes) {
609         if(autoSaveTimer == null)
610             autoSaveTimer = new AutoSaveTimer();
611
612         removeScheduledTimer(autoSaveTimer);
613
614         if(enabled)
615             addScheduledTimer(autoSaveTimer, delayInMinutes, false);
616     }
617
618     public static class AutoSaveTimer implements XJScheduledTimerDelegate {
619         public void scheduledTimerFired(boolean startup) {
620             for (XJDocument document : documents) {
621                 if (document.isDirty() && document.getDocumentPath() != null) {
622                     document.performSave(false);
623                 }
624             }
625         }
626     }
627
628     // *** Events
629

630     public void performPreferences() {
631         displayPrefs();
632     }
633
634     public void performQuit() {
635         delegate.appWillTerminate();
636         Iterator JavaDoc<XJDocument> iterator = documents.iterator();
637         while(iterator.hasNext()) {
638             XJDocument document = iterator.next();
639             if(document.performClose())
640                 iterator = documents.iterator();
641             else
642                 return;
643         }
644         XJFrame.closeDesktop();
645         shutdown();
646     }
647
648     // Properties
649

650     public boolean supportsPersistence() {
651         return delegate == null || delegate.supportsPersistence();
652     }
653
654     public boolean hasPreferencesMenuItem() {
655         return delegate == null || delegate.appHasPreferencesMenuItem();
656     }
657
658     public boolean shouldQuitAfterLastWindowClosed() {
659         return delegate != null && delegate.appShouldQuitAfterLastWindowClosed();
660     }
661
662     public boolean useDesktopMode() {
663         return useDesktopMode;
664     }
665
666     public Class JavaDoc getPreferencesClass() {
667         if(delegate == null)
668             return XJApplication.class;
669         else
670             return delegate.appPreferencesClass();
671     }
672
673 }
674
Popular Tags