/* * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI * for visualizing and manipulating spatial features with geometry and attributes. * * Copyright (C) 2003 Vivid Solutions * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * For more information, contact: * * Vivid Solutions * Suite #1A * 2328 Government Street * Victoria BC V8T 5G5 * Canada * * (250)385-6040 * www.vividsolutions.com */ package com.vividsolutions.jump.workbench; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Font; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridLayout; import java.awt.Image; import java.awt.Insets; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JWindow; import javax.swing.UIManager; import javax.swing.plaf.FontUIResource; import org.openjump.OpenJumpConfiguration; import com.vividsolutions.jump.I18N; import com.vividsolutions.jump.task.TaskMonitor; import com.vividsolutions.jump.util.Blackboard; import com.vividsolutions.jump.util.LangUtil; import com.vividsolutions.jump.util.StringUtil; import com.vividsolutions.jump.util.commandline.CommandLine; import com.vividsolutions.jump.util.commandline.OptionSpec; import com.vividsolutions.jump.util.commandline.ParseException; import com.vividsolutions.jump.workbench.driver.DriverManager; import com.vividsolutions.jump.workbench.plugin.PlugInManager; import com.vividsolutions.jump.workbench.ui.SplashPanel; import com.vividsolutions.jump.workbench.ui.SplashWindow; import com.vividsolutions.jump.workbench.ui.WorkbenchFrame; import com.vividsolutions.jump.workbench.ui.images.IconLoader; import com.vividsolutions.jump.workbench.ui.plugin.PersistentBlackboardPlugIn; /** * This class is responsible for setting up and displaying the main JUMP * workbench window. */ public class JUMPWorkbench { private static ImageIcon splashImage; public static ImageIcon splashImage() { // Lazily initialize it, as it may not even be called (e.g. EZiLink), // and we want the splash screen to appear ASAP [Jon Aquino] if (splashImage == null) { splashImage = IconLoader.icon("splash.png"); //splashImage = IconLoader.icon(I18N.get("splash.png")); } return splashImage; } private static ArrayList<Image> appIcons(){ ArrayList iconlist = new ArrayList(); iconlist.add(IconLoader.image("oj_16_Kplain2oj.png")); iconlist.add(IconLoader.image("oj_24.png")); iconlist.add(IconLoader.image("oj_32.png")); iconlist.add(IconLoader.image("oj_48.png")); iconlist.add(IconLoader.image("oj_256.png")); //java.util.Collections.reverse(iconlist); return iconlist; } // for java 1.5- public static final ImageIcon APP_ICON = IconLoader.icon("app-icon.gif"); // for java 1.6+ public static final ArrayList APP_ICONS = appIcons(); public static final String VERSION_TEXT = I18N.get("JUMPWorkbench.version.number"); //-- dont change the following strings public final static String PROPERTIES_OPTION = "properties"; public final static String DEFAULT_PLUGINS = "default-plugins"; public final static String PLUG_IN_DIRECTORY_OPTION = "plug-in-directory"; public final static String I18N_FILE = "i18n"; public static final String INITIAL_PROJECT_FILE = "project"; public static final String STATE_OPTION = "state"; // Added by STanner to allow I18N to have access to this public static String I18N_SETLOCALE = ""; private static Class progressMonitorClass = SingleLineProgressMonitor.class; //<<TODO:REFACTORING>> Move images package under // com.vividsolutions.jump.workbench //to avoid naming conflicts with other libraries. [Jon Aquino] private static CommandLine commandLine; private WorkbenchContext context = new JUMPWorkbenchContext(this); private WorkbenchFrame frame; private DriverManager driverManager = new DriverManager(frame); private WorkbenchProperties dummyProperties = new WorkbenchProperties() { public List getPlugInClasses() { return new ArrayList(); } public List getPlugInClasses(ClassLoader classLoader) { return new ArrayList(); } public List getInputDriverClasses() { return new ArrayList(); } public List getOutputDriverClasses() { return new ArrayList(); } public List getConfigurationClasses() { return new ArrayList(); } }; private WorkbenchProperties properties = dummyProperties; private PlugInManager plugInManager; private Blackboard blackboard = new Blackboard(); /** * @param o * a window to decorate with icon */ public static void setIcon ( Object o ) { // attach the right icon, depending on // - availability of method setIconImages (java 1.5 vs. 1.6), several icons for different sizes // - underlying object type (JFrame, JInternalFrame, others? ) // let's go if ( o instanceof JFrame ) { JFrame f = (JFrame) o; try{ // case java 1.6+ Class[] types = {java.util.List.class}; java.lang.reflect.Method method = JFrame.class.getMethod("setIconImages",types); Object[] params = {APP_ICONS}; method.invoke( f,params ); //System.out.println("jep"); }catch( Exception e ) { // case java 1.5-, is really bad with transparent pngs, so we stick with the old gif f.setIconImage((Image)APP_ICON.getImage()); //System.out.println("noe"); } } else if ( o instanceof javax.swing.JInternalFrame ) { //System.out.println("internal"); javax.swing.JInternalFrame f = (javax.swing.JInternalFrame) o; f.setFrameIcon(getIcon()); } } private static ImageIcon icon ; public static ImageIcon getIcon(){ // java 1.5 is really bad with transparent pngs, so we stick with the old gif if ( ! ( icon instanceof ImageIcon ) ) { Double jre_version = Double.parseDouble( System.getProperty("java.version").substring(0,3) ); if ( jre_version < 1.6 ) { icon = APP_ICON; } else { icon = new ImageIcon(); icon.setImage((Image)APP_ICONS.get(0)); } } return icon; } /** * @param s * a visible SplashWindow to close when initialization is * complete and the WorkbenchFrame is opened */ public JUMPWorkbench(String title, String[] args, final JWindow s, TaskMonitor monitor) throws Exception { frame = new WorkbenchFrame(title, context); frame.addWindowListener(new WindowAdapter() { public void windowOpened(WindowEvent e) { s.setVisible(false); } }); boolean defaultFileExists = false; //[sstein 6.July.2008] new File defaultFile = null; if (commandLine.hasOption(DEFAULT_PLUGINS)) { defaultFile = new File(commandLine.getOption( DEFAULT_PLUGINS).getArg(0)); if (defaultFile.exists()) { defaultFileExists = true; //[sstein 6.July.2008] disabled to enable loading of two properties files //properties = new WorkbenchPropertiesFile(defaultFile, frame); } else { System.out.println("JUMP: Warning: Default plugins file does not exist: " + defaultFile); } } boolean propertiesFileExists = false; //[sstein 6.July.2008] new File propertiesFile = null; if (commandLine.hasOption(PROPERTIES_OPTION)) { propertiesFile = new File(commandLine.getOption( PROPERTIES_OPTION).getArg(0)); if (propertiesFile.exists()) { //[sstein 6.July.2008] disabled to enable loading of two properties files //properties = new WorkbenchPropertiesFile(propertiesFile, frame); propertiesFileExists = true; } else { System.out.println("JUMP: Warning: Properties file does not exist: " + propertiesFile); } } //-- [sstein 6.July.2008] start new if((defaultFileExists) && (propertiesFileExists)){ properties = new WorkbenchPropertiesFile(defaultFile, propertiesFile, frame); } else if(defaultFileExists){ properties = new WorkbenchPropertiesFile(defaultFile, frame); } else if(propertiesFileExists){ properties = new WorkbenchPropertiesFile(propertiesFile, frame); } //-- end new File extensionsDirectory = null; if (commandLine.hasOption(PLUG_IN_DIRECTORY_OPTION)) { extensionsDirectory = new File(commandLine.getOption( PLUG_IN_DIRECTORY_OPTION).getArg(0)); if (!extensionsDirectory.exists()) { System.out .println("JUMP: Warning: Extensions directory does not exist: " + extensionsDirectory); extensionsDirectory = null; } } else { extensionsDirectory = new File("../lib/ext"); if (!extensionsDirectory.exists()) { // Added further information so that debug user will know where // it is actually looking for as the extension directory. [Ed Deen] System.out .println("JUMP: Warning: Extensions directory does not exist: " + extensionsDirectory + " where homedir = [" + System.getProperty("user.dir") + "]"); extensionsDirectory = null; } } if (commandLine.hasOption( INITIAL_PROJECT_FILE )) { String task = commandLine.getOption( INITIAL_PROJECT_FILE ).getArg(0); this.getBlackboard().put( INITIAL_PROJECT_FILE, task ); } if(commandLine.hasOption(STATE_OPTION)) { File option = new File(commandLine.getOption(STATE_OPTION).getArg(0)); if(option.isDirectory()) { PersistentBlackboardPlugIn.setPersistenceDirectory(option.getPath()); } if(option.isFile()) { PersistentBlackboardPlugIn.setFileName(option.getName()); PersistentBlackboardPlugIn.setPersistenceDirectory(option.getAbsoluteFile().getParent()); } } plugInManager = new PlugInManager(context, extensionsDirectory, monitor); //Load drivers before initializing the frame because part of the frame //initialization is the initialization of the driver dialogs. [Jon // Aquino] //The initialization of some plug-ins (e.g. LoadDatasetPlugIn) requires // that //the drivers be loaded. Thus load the drivers here, before the // plug-ins //are initialized. driverManager.loadDrivers(properties); } public static void main(String[] args) { try { // first fetch parameters, locale might be changed with -i18n switch parseCommandLine(args); // load i18n specified in command line ( '-i18n translation' ) if (commandLine.hasOption(I18N_FILE)) { I18N.loadFile(commandLine.getOption(I18N_FILE).getArg(0)); I18N_SETLOCALE = commandLine.getOption(I18N_FILE).getArg(0); } // Init the L&F before instantiating the progress monitor [Jon Aquino] initLookAndFeel(); // setFont to switch fonts if defaults cannot display current language [ede] // this changes the default font definition of the jre, first internationalized // string shown is 'JUMPWorkbench.version' on splashpanel setFont(); ProgressMonitor progressMonitor = (ProgressMonitor) progressMonitorClass .newInstance(); SplashPanel splashPanel = new SplashPanel(splashImage(), I18N.get("JUMPWorkbench.version")+" " + VERSION_TEXT ); splashPanel.add(progressMonitor, new GridBagConstraints(0, 10, 1, 1, 1, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 10), 0, 0)); main(args, I18N.get("JUMPWorkbench.jump"), new JUMPConfiguration(), splashPanel, progressMonitor); } catch (Throwable t) { WorkbenchFrame.handleThrowable(t, null); } } /** * setupClass is specified as a String to prevent it from being loaded * before we display the splash screen, in case setupClass takes a long time * to load. * @param args main application arguments * @param title application title * @param setup an object implementing the Setup interface * (e.g. JUMPConfiguration) * @param splashComponent * a component to open until the workbench frame is displayed * @param taskMonitor * notified of progress of plug-in loading */ public static void main(String[] args, String title, Setup setup, JComponent splashComponent, TaskMonitor taskMonitor) { try { //I don't know if we still need to specify the SAX driver [Jon // Aquino 10/30/2003] // disabled by ede 09/2011 //System.setProperty("org.xml.sax.driver","org.apache.xerces.parsers.SAXParser"); // already initialized in main() above [ede] //initLookAndFeel(); SplashWindow splashWindow = new SplashWindow(splashComponent); splashWindow.setVisible(true); JUMPWorkbench workbench = new JUMPWorkbench(title, args, splashWindow, taskMonitor); setup.setup(workbench.context); //must wait until after setup initializes the persistent blackboard to recall settings WorkbenchFrame frame = workbench.getFrame(); frame.setLocation(frame.recallWindowLocation()); frame.setSize(frame.recallWindowSize()); if (frame.recallMaximizedState()) frame.setExtendedState(Frame.MAXIMIZED_BOTH); workbench.context.getWorkbench().getPlugInManager().load(); OpenJumpConfiguration.postExtensionInitialization(workbench.context); workbench.getFrame().setVisible(true); } catch (Throwable t) { WorkbenchFrame.handleThrowable(t, null); } } private static void initLookAndFeel() throws Exception { if (LangUtil.ifNull(System.getProperty("initLookAndFeel"), "true") .toString().equalsIgnoreCase("false")) { return; } //Apple stuff from Raj Singh's startup script [Jon Aquino 10/30/2003] System.setProperty("apple.laf.useScreenMenuBar", "true"); System.setProperty("apple.awt.showGrowBox", "true"); if (UIManager.getLookAndFeel() != null && UIManager.getLookAndFeel().getClass().getName().equals( UIManager.getSystemLookAndFeelClassName())) { return; } String laf = System.getProperty( "swing.defaultlaf" ); if ( laf == null ){ laf = UIManager.getSystemLookAndFeelClassName(); } UIManager.setLookAndFeel( laf ); } // this is in preparation that we might want to support more fonts in the // future private static Font[] loadFonts() throws Exception { Font font = Font.createFont(Font.TRUETYPE_FONT, Class.class.getClass() .getResource("/language/fonts/code2000.ttf").openStream()); // since 1.6 we could register the font and use it by name // but using the font directly makes us 1.5 compatible // GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont( font // ); return new Font[] { font }; } private static boolean setFont() throws Exception { String test = I18N.get("ui.MenuNames.FILE"); boolean replaced = false; Font font = null; java.util.Enumeration keys = UIManager.getDefaults().keys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); Object value = UIManager.get(key); // loop over fontuires entries if (value instanceof javax.swing.plaf.FontUIResource) { FontUIResource fold = ((javax.swing.plaf.FontUIResource) value); // can default font display test sentence? if (fold.canDisplayUpTo(test) != -1) { // fetch replacement candidate if (font == null) font = loadFonts()[0]; // copy attributes Map attrs = fold.getAttributes(); // remove family attribute java.text.AttributedCharacterIterator.Attribute fam = null; for (Iterator iterator = attrs.keySet().iterator(); iterator .hasNext();) { fam = (java.text.AttributedCharacterIterator.Attribute) iterator .next(); if (fam.toString().equals( "java.awt.font.TextAttribute(family)")) { break; } } if (fam != null) attrs.remove(fam); // create the new fontuires FontUIResource fnew = new javax.swing.plaf.FontUIResource( font.deriveFont(attrs)); // check if new font can display and set if (fnew.canDisplayUpTo(test) == -1) { UIManager.put(key, fnew); replaced = true; } } } } /* * // show all registered available fonts GraphicsEnvironment e = * GraphicsEnvironment.getLocalGraphicsEnvironment(); for (String foo : * e.getAvailableFontFamilyNames()){ System.out.println(foo); } */ // replaced any? return replaced; } public DriverManager getDriverManager() { return driverManager; } /** * The properties file; not to be confused with the WorkbenchContext * properties. */ public WorkbenchProperties getProperties() { return properties; } public WorkbenchFrame getFrame() { return frame; } public WorkbenchContext getContext() { return context; } private static void parseCommandLine(String[] args) throws WorkbenchException { //<<TODO:QUESTION>> Notify MD: using CommandLine [Jon Aquino] commandLine = new CommandLine('-'); commandLine.addOptionSpec(new OptionSpec(PROPERTIES_OPTION, 1)); commandLine.addOptionSpec(new OptionSpec(DEFAULT_PLUGINS, 1)); commandLine.addOptionSpec(new OptionSpec(PLUG_IN_DIRECTORY_OPTION, 1)); commandLine.addOptionSpec(new OptionSpec(I18N_FILE, 1)); //[UT] 17.08.2005 commandLine.addOptionSpec(new OptionSpec( INITIAL_PROJECT_FILE, 1)); commandLine.addOptionSpec(new OptionSpec(STATE_OPTION, 1)); try { commandLine.parse(args); } catch (ParseException e) { throw new WorkbenchException( "A problem occurred parsing the command line: " + e.toString()); } } private static void addProperties(WorkbenchProperties oldProperties, WorkbenchProperties newProperties) throws Exception{ oldProperties.getPlugInClasses().addAll(newProperties.getPlugInClasses()); oldProperties.getInputDriverClasses().addAll(newProperties.getInputDriverClasses()); oldProperties.getOutputDriverClasses().addAll(newProperties.getOutputDriverClasses()); oldProperties.getConfigurationClasses().addAll(newProperties.getConfigurationClasses()); } public PlugInManager getPlugInManager() { return plugInManager; } //<<TODO>> Make some properties persistent using a #makePersistent(key) // method. [Jon Aquino] /** * Expensive data structures can be cached on the blackboard so that several * plug-ins can share them. */ public Blackboard getBlackboard() { return blackboard; } private static abstract class ProgressMonitor extends JPanel implements TaskMonitor { private Component component; public ProgressMonitor(Component component) { this.component = component; setLayout(new BorderLayout()); add(component, BorderLayout.CENTER); setOpaque(false); } protected Component getComponent() { return component; } protected abstract void addText(String s); public void report(String description) { addText(description); } public void report(int itemsDone, int totalItems, String itemDescription) { addText(itemsDone + " / " + totalItems + " " + itemDescription); } public void report(Exception exception) { addText(StringUtil.toFriendlyName(exception.getClass().getName())); } public void allowCancellationRequests() { } public boolean isCancelRequested() { return false; } } private static class VerticallyScrollingProgressMonitor extends ProgressMonitor { private static int ROWS = 3; private JLabel[] labels; public VerticallyScrollingProgressMonitor() { super(new JPanel(new GridLayout(ROWS, 1))); JPanel panel = (JPanel) getComponent(); panel.setOpaque(false); labels = new JLabel[ROWS]; for (int i = 0; i < ROWS; i++) { //" " not "", to give the label some height. [Jon Aquino] labels[i] = new JLabel(" "); labels[i].setFont(labels[i].getFont().deriveFont(Font.BOLD)); panel.add(labels[i]); } } protected void addText(String s) { for (int i = 0; i < (ROWS - 1); i++) { //-1 labels[i].setText(labels[i + 1].getText()); } labels[ROWS - 1].setText(s); } } private static class SingleLineProgressMonitor extends ProgressMonitor { public SingleLineProgressMonitor() { super(new JLabel(" ")); ((JLabel) getComponent()).setFont(((JLabel) getComponent()) .getFont().deriveFont(Font.BOLD)); ((JLabel) getComponent()).setHorizontalAlignment(JLabel.LEFT); } protected void addText(String s) { ((JLabel) getComponent()).setText(s); } } private static class HorizontallyScrollingProgressMonitor extends ProgressMonitor { private static final String BUFFER = " "; public HorizontallyScrollingProgressMonitor() { super(new JLabel(" ")); ((JLabel) getComponent()).setFont(((JLabel) getComponent()) .getFont().deriveFont(Font.BOLD)); ((JLabel) getComponent()).setHorizontalAlignment(JLabel.RIGHT); } protected void addText(String s) { ((JLabel) getComponent()).setText(BUFFER + s + ((JLabel) getComponent()).getText()); } } }