1 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 ; 54 import java.util.ArrayList ; 55 import java.util.Iterator ; 56 import java.util.List ; 57 import java.util.TimerTask ; 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 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 <XJScheduledTimer> scheduledTimers = new ArrayList <XJScheduledTimer>(); 70 protected static final long SCHEDULED_TIMER_MINUTES = 1; 71 72 protected static List <XJDocument> documents = new ArrayList <XJDocument>(); 73 protected static List <XJWindow> windows = new ArrayList <XJWindow>(); 74 75 public static final int MAX_RECENT_FILES = 10; 76 protected static List <String > 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 <XJDocumentType> documentType = new ArrayList <XJDocumentType>(); 83 protected static String propertiesPath = ""; 84 85 protected static boolean startingUp = true; 86 protected static String [] launchArguments = null; 87 protected static List <String > documentsToOpenAtStartup = new ArrayList <String >(); 88 89 protected static String 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 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 getAppVersionShort() { 123 return delegate.appVersionShort(); 124 } 125 126 public static String 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 <String >(); 150 XJMainMenuBar.refreshAllRecentFilesMenu(); 151 } 152 153 public static void run(XJApplicationDelegate delegate, String [] args, String 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 [] args) { 164 setDelegate(delegate); 165 launchArguments = args; 166 useDesktopMode = XJApplication.delegate.useDesktopMode(); 167 168 SwingUtilities.invokeLater(new Runnable () { 169 public void run() { 170 XJApplication.startingUp = false; 171 XJApplication.delegate.appDidLaunch(launchArguments, documentsToOpenAtStartup); 172 documentsToOpenAtStartup.clear(); 173 new java.util.Timer ().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 { 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 path) { 221 propertiesPath = path; 222 } 223 224 public static String getPropertiesPath() { 225 return propertiesPath; 226 } 227 228 public String 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 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 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 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 recentFiles() { 307 return recentFiles; 308 } 309 310 312 protected void addPreferencesMenuItem() { 313 } 314 315 protected void removePreferencesMenuItem() { 316 } 317 318 public void refreshMainMenuBar() { 319 XJMainMenuBar.refreshAllMenuBars(); 320 } 321 322 324 public static void addDocumentType(Class documentClass, Class windowClass, Class dataClass, String ext, String description) { 325 documentType.add(new XJDocumentType(documentClass, windowClass, dataClass, ext, description)); 326 } 327 328 public static void addDocumentType(Class documentClass, Class windowClass, Class dataClass, String [] ext, String description) { 329 documentType.add(new XJDocumentType(documentClass, windowClass, dataClass, ext, description)); 330 } 331 332 public XJDocumentType getDocumentTypeForPath(String 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 dc) { 344 for (XJDocumentType doc : documentType) { 345 if (doc.getDataClass().equals(dc)) 346 return doc; 347 } 348 return null; 349 } 350 351 public List getDocumentExtensions() { 352 List <List > ext = new ArrayList <List >(); 353 for (XJDocumentType doc : documentType) { 354 ext.add(doc.getExtensions()); 355 } 356 return ext; 357 } 358 359 public List <String > getDocumentDescriptions() { 360 List <String > descr = new ArrayList <String >(); 361 for (XJDocumentType doc : documentType) { 362 descr.add(doc.getDescriptionString()); 363 } 364 return descr; 365 } 366 367 public List <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 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 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 <String > files) { 444 boolean success = true; 445 for(String file : files) { 446 if(!openDocument(file)) success = false; 447 } 448 return success; 449 } 450 451 public boolean openDocument(String file) { 452 if(file == null) 453 return false; 454 455 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 file = recentFiles.get(0); 496 while(!new File (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 if (document.getWindow() != null && document.getWindow().isActive()) 537 return document; 538 } 539 return null; 540 } 541 542 public XJDocument getDocumentForPath(String path) { 543 for (XJDocument document : documents) { 544 String 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 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 SwingUtilities.invokeLater(new Runnable () { 584 public void run() { 585 performQuit(); 586 } 587 }); 588 } 589 } 590 } 591 592 public List <XJWindow> getWindows() { 593 return windows; 594 } 595 596 public List <XJWindow> getWindowsInWindowMenu() { 597 List <XJWindow> wim = new ArrayList <XJWindow>(); 598 for(XJWindow w : windows) { 599 if(w.shouldAppearsInWindowMenu()) { 600 wim.add(w); 601 } 602 } 603 return wim; 604 } 605 606 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 630 public void performPreferences() { 631 displayPrefs(); 632 } 633 634 public void performQuit() { 635 delegate.appWillTerminate(); 636 Iterator <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 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 getPreferencesClass() { 667 if(delegate == null) 668 return XJApplication.class; 669 else 670 return delegate.appPreferencesClass(); 671 } 672 673 } 674 | Popular Tags |