@edu.umd.cs.findbugs.annotations.SuppressWarnings({ "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", "SC_START_IN_CTOR" }) // "only one application at a time. The thread is only called to help improve user experiance // when opening the preferences, it is not critical for it to be run at this stage" public Apps(JFrame frame) { super(true); long start = System.nanoTime(); splash(false); splash(true, true); setButtonSpace(); setJynstrumentSpace(); jmri.Application.setLogo(logo()); jmri.Application.setURL(line2()); // Enable proper snapping of JSliders SliderSnap.init(); // Prepare font lists prepareFontLists(); // install shutdown manager InstanceManager.setShutDownManager(new DefaultShutDownManager()); // add the default shutdown task to save blocks // as a special case, register a ShutDownTask to write out blocks InstanceManager.shutDownManagerInstance() .register( new AbstractShutDownTask("Writing Blocks") { @Override public boolean execute() { // Save block values prior to exit, if necessary log.debug("Start writing block info"); try { new BlockValueFile().writeBlockValues(); } // catch (org.jdom2.JDOMException jde) { log.error("Exception writing blocks: {}", // jde); } catch (IOException ioe) { log.error("Exception writing blocks: {}", ioe); } // continue shutdown return true; } }); // Get configuration profile // Needs to be done before loading a ConfigManager or UserPreferencesManager FileUtil.createDirectory(FileUtil.getPreferencesPath()); // Needs to be declared final as we might need to // refer to this on the Swing thread final File profileFile; profileFilename = configFilename.replaceFirst(".xml", ".properties"); // decide whether name is absolute or relative if (!new File(profileFilename).isAbsolute()) { // must be relative, but we want it to // be relative to the preferences directory profileFile = new File(FileUtil.getPreferencesPath() + profileFilename); } else { profileFile = new File(profileFilename); } ProfileManager.getDefault().setConfigFile(profileFile); // See if the profile to use has been specified on the command line as // a system property jmri.profile as a profile id. if (System.getProperties().containsKey(ProfileManager.SYSTEM_PROPERTY)) { ProfileManager.getDefault() .setActiveProfile(System.getProperty(ProfileManager.SYSTEM_PROPERTY)); } // @see jmri.profile.ProfileManager#migrateToProfiles JavaDoc for conditions handled here if (!ProfileManager.getDefault().getConfigFile().exists()) { // no profile config for this app try { if (ProfileManager.getDefault() .migrateToProfiles(configFilename)) { // migration or first use // notify user of change only if migration occured // TODO: a real migration message JOptionPane.showMessageDialog( sp, Bundle.getMessage("ConfigMigratedToProfile"), jmri.Application.getApplicationName(), JOptionPane.INFORMATION_MESSAGE); } } catch (IOException | IllegalArgumentException ex) { JOptionPane.showMessageDialog( sp, ex.getLocalizedMessage(), jmri.Application.getApplicationName(), JOptionPane.ERROR_MESSAGE); log.error(ex.getMessage()); } } try { ProfileManagerDialog.getStartingProfile(sp); // Manually setting the configFilename property since calling // Apps.setConfigFilename() does not reset the system property configFilename = FileUtil.getProfilePath() + Profile.CONFIG_FILENAME; System.setProperty("org.jmri.Apps.configFilename", Profile.CONFIG_FILENAME); log.info("Starting with profile {}", ProfileManager.getDefault().getActiveProfile().getId()); } catch (IOException ex) { log.info( "Profiles not configurable. Using fallback per-application configuration. Error: {}", ex.getMessage()); } // Install configuration manager and Swing error handler ConfigureManager cm = new JmriConfigurationManager(); InstanceManager.store(cm, ConfigureManager.class); InstanceManager.setDefault(ConfigureManager.class, cm); // Install a history manager InstanceManager.store(new FileHistory(), FileHistory.class); // record startup InstanceManager.getDefault(FileHistory.class).addOperation("app", nameString, null); // Install a user preferences manager InstanceManager.store( DefaultUserMessagePreferences.getInstance(), UserPreferencesManager.class); InstanceManager.store(new NamedBeanHandleManager(), NamedBeanHandleManager.class); // Install an IdTag manager InstanceManager.store(new DefaultIdTagManager(), IdTagManager.class); // Install Entry Exit Pairs Manager InstanceManager.store(new EntryExitPairs(), EntryExitPairs.class); // install preference manager InstanceManager.store(new TabbedPreferences(), TabbedPreferences.class); // Install abstractActionModel InstanceManager.store(new apps.CreateButtonModel(), apps.CreateButtonModel.class); // find preference file and set location in configuration manager // Needs to be declared final as we might need to // refer to this on the Swing thread final File file; File singleConfig; File sharedConfig = null; // decide whether name is absolute or relative if (!new File(configFilename).isAbsolute()) { // must be relative, but we want it to // be relative to the preferences directory singleConfig = new File(FileUtil.getUserFilesPath() + configFilename); } else { singleConfig = new File(configFilename); } try { // get preferences file sharedConfig = FileUtil.getFile(FileUtil.PROFILE + Profile.SHARED_CONFIG); if (!sharedConfig.canRead()) { sharedConfig = null; } } catch (FileNotFoundException ex) { // ignore - sharedConfig will remain null in this case } // load config file if it exists if (sharedConfig != null) { file = sharedConfig; } else { file = singleConfig; } log.debug("Using config file(s) {}", file.getPath()); if (file.exists()) { log.debug("start load config file {}", file.getPath()); try { configOK = InstanceManager.configureManagerInstance().load(file, true); } catch (JmriException e) { log.error("Unhandled problem loading configuration", e); configOK = false; } log.debug("end load config file, OK={}", configOK); } else { log.info( "No saved preferences, will open preferences window. Searched for {}", file.getPath()); configOK = false; } // Add actions to abstractActionModel // Done here as initial non-GUI initialisation is completed // and UI L&F has been set addToActionModel(); // populate GUI log.debug("Start UI"); setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); // Create a WindowInterface object based on the passed-in Frame JFrameInterface wi = new JFrameInterface(frame); // Create a menu bar menuBar = new JMenuBar(); // Create menu categories and add to the menu bar, add actions to menus createMenus(menuBar, wi); // done long end = System.nanoTime(); long elapsedTime = (end - start) / 1000000; /* This ensures that the message is displayed on the screen for a minimum of 2.5seconds, if the time taken to get to this point in the code is longer that 2.5seconds then the wait is not invoked. */ long sleep = 2500 - elapsedTime; if (sleep > 0) { log.debug( "Debug message was displayed for less than 2500ms ({}ms). Sleeping for {}ms to allow user sufficient time to do something.", elapsedTime, sleep); try { Thread.sleep(sleep); } catch (InterruptedException e) { log.error(e.getLocalizedMessage(), e); } } FileUtil.logFilePaths(); splash(false); splash(true, false); Toolkit.getDefaultToolkit().removeAWTEventListener(debugListener); while (debugmsg) { /*The user has pressed the interupt key that allows them to disable logixs at start up we do not want to process any more information until the user has answered the question */ try { Thread.sleep(1000); } catch (InterruptedException e) { log.error(e.getLocalizedMessage(), e); } } // Now load deferred config items if (file.exists() && file.equals(singleConfig)) { // To avoid possible locks, deferred load should be // performed on the Swing thread if (SwingUtilities.isEventDispatchThread()) { configDeferredLoadOK = doDeferredLoad(file); } else { try { // Use invokeAndWait method as we don't want to // return until deferred load is completed SwingUtilities.invokeAndWait( new Runnable() { @Override public void run() { configDeferredLoadOK = doDeferredLoad(file); } }); } catch (InterruptedException | InvocationTargetException ex) { log.error("Exception creating system console frame", ex); } } } else { configDeferredLoadOK = false; } // If preferences need to be migrated, do it now if (sharedConfig == null && configOK == true && configDeferredLoadOK == true) { log.info("Migrating preferences to new format..."); // migrate preferences InstanceManager.tabbedPreferencesInstance().init(); InstanceManager.tabbedPreferencesInstance().saveContents(); InstanceManager.configureManagerInstance().storePrefs(); // notify user of change log.info("Preferences have been migrated to new format."); log.info("New preferences format will be used after JMRI is restarted."); if (!GraphicsEnvironment.isHeadless()) { JOptionPane.showMessageDialog( sp, Bundle.getMessage( "SingleConfigMigratedToSharedConfig", ProfileManager.getDefault().getActiveProfile().getName()), jmri.Application.getApplicationName(), JOptionPane.INFORMATION_MESSAGE); } } /*Once all the preferences have been loaded we can initial the preferences doing it in a thread at this stage means we can let it work in the background*/ Runnable r = new Runnable() { @Override public void run() { try { InstanceManager.tabbedPreferencesInstance().init(); } catch (Exception ex) { log.error("Error trying to setup preferences {}", ex.getLocalizedMessage(), ex); } } }; Thread thr = new Thread(r, "initialize preferences"); thr.start(); // Initialise the decoderindex file instance within a seperate thread to help improve first use // perfomance r = new Runnable() { @Override public void run() { try { DecoderIndexFile.instance(); } catch (Exception ex) { log.error("Error in trying to initialize decoder index file {}", ex.toString()); } } }; Thread thr2 = new Thread(r, "initialize decoder index"); thr2.start(); if (Boolean.getBoolean("org.jmri.python.preload")) { r = new Runnable() { public void run() { try { JmriScriptEngineManager.getDefault().initializeAllEngines(); } catch (Exception ex) { log.error("Error in trying to initialize python interpreter {}", ex.toString()); } } }; Thread thr3 = new Thread(r, "initialize python interpreter"); thr3.start(); } // if the configuration didn't complete OK, pop the prefs frame and help log.debug("Config go OK? {}", (configOK || configDeferredLoadOK)); if (!configOK || !configDeferredLoadOK) { HelpUtil.displayHelpRef("package.apps.AppConfigPanelErrorPage"); doPreferences(); } log.debug("Done with doPreferences, start statusPanel"); add(statusPanel()); log.debug("Done with statusPanel, start buttonSpace"); add(buttonSpace()); add(_jynstrumentSpace); long eventMask = AWTEvent.MOUSE_EVENT_MASK; Toolkit.getDefaultToolkit() .addAWTEventListener( new AWTEventListener() { @Override public void eventDispatched(AWTEvent e) { if (e instanceof MouseEvent) { MouseEvent me = (MouseEvent) e; if (me.isPopupTrigger() && me.getComponent() instanceof JTextComponent) { final JTextComponent component = (JTextComponent) me.getComponent(); final JPopupMenu menu = new JPopupMenu(); JMenuItem item; item = new JMenuItem(new DefaultEditorKit.CopyAction()); item.setText("Copy"); item.setEnabled(component.getSelectionStart() != component.getSelectionEnd()); menu.add(item); item = new JMenuItem(new DefaultEditorKit.CutAction()); item.setText("Cut"); item.setEnabled( component.isEditable() && component.getSelectionStart() != component.getSelectionEnd()); menu.add(item); item = new JMenuItem(new DefaultEditorKit.PasteAction()); item.setText("Paste"); item.setEnabled(component.isEditable()); menu.add(item); menu.show(me.getComponent(), me.getX(), me.getY()); } } } }, eventMask); // do final activation InstanceManager.logixManagerInstance().activateAllLogixs(); InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager.class) .initializeLayoutBlockPaths(); // Loads too late - now started from ItemPalette // new jmri.jmrit.catalog.configurexml.DefaultCatalogTreeManagerXml().readCatalogTrees(); log.debug("End constructor"); }
/** Adds the development menu to the default main menu bar. */ @Override protected void createMenus(JMenuBar menuBar, WindowInterface wi) { super.createMenus(menuBar, wi); developmentMenu(menuBar, wi); menuBar.add(new jmri.jmris.ServerMenu()); }