3 import java.awt.BorderLayout;
4 import java.awt.Component;
6 import java.awt.event.WindowAdapter;
7 import java.awt.event.WindowEvent;
9 import java.io.FileNotFoundException;
10 import java.util.ArrayList;
11 import java.util.Locale;
13 import javax.swing.JFrame;
14 import javax.swing.JSplitPane;
15 import javax.swing.JToolBar;
16 import javax.swing.UIManager;
17 import javax.swing.WindowConstants;
19 import tim.prune.config.Config;
20 import tim.prune.config.ConfigException;
21 import tim.prune.gui.DetailsDisplay;
22 import tim.prune.gui.IconManager;
23 import tim.prune.gui.MenuManager;
24 import tim.prune.gui.SelectorDisplay;
25 import tim.prune.gui.SidebarController;
26 import tim.prune.gui.StatusBar;
27 import tim.prune.gui.Viewport;
28 import tim.prune.gui.map.MapCanvas;
29 import tim.prune.gui.profile.ProfileChart;
32 * GpsPrune is a tool to visualize, edit, convert and prune GPS data
33 * Please see the included readme.txt or https://activityworkshop.net
34 * This software is copyright activityworkshop.net 2006-2020 and made available through the Gnu GPL version 2.
35 * For license details please see the included license.txt.
36 * GpsPrune is the main entry point to the application, including initialisation and launch
40 /** Version number of application, used in about screen and for version check */
41 public static final String VERSION_NUMBER = "20";
42 /** Build number, just used for about screen */
43 public static final String BUILD_NUMBER = "378";
44 /** Static reference to App object */
45 private static App APP = null;
47 /** Program name, used for Frame title and for Macs also on the system bar */
48 private static final String PROGRAM_NAME = "GpsPrune";
53 * @param args command line arguments
55 public static void main(String[] args)
58 String localeCode = null;
59 String langFilename = null;
60 String configFilename = null;
61 ArrayList<File> dataFiles = new ArrayList<File>();
62 boolean showUsage = false;
64 // Mac OSX - specific properties (Mac insists that this is done as soon as possible)
65 if (System.getProperty("mrj.version") != null) {
66 System.setProperty("apple.laf.useScreenMenuBar", "true"); // menu at top of screen
67 System.setProperty("com.apple.mrj.application.apple.menu.about.name", PROGRAM_NAME);
69 // Loop over given arguments, if any
70 for (int i=0; i<args.length; i++)
73 if (arg.startsWith("--lang="))
75 localeCode = arg.substring(7);
76 locale = getLanguage(localeCode);
78 else if (arg.startsWith("--langfile="))
80 langFilename = arg.substring(11);
82 else if (arg.startsWith("--configfile="))
84 configFilename = arg.substring(13);
86 else if (arg.startsWith("--help")) {
91 // Check if a data file has been given
92 File f = new File(arg);
93 if (f.exists() && f.isFile() && f.canRead()) {
98 // Make a useful String from the unknown parameter - could it be a mistyped filename?
99 System.out.println(makeUnknownParameterString(arg));
106 System.out.println("GpsPrune - a tool for editing GPS data.\nPossible parameters:"
107 + "\n --configfile=<file> used to specify a configuration file"
108 + "\n --lang=<code> used to specify language code such as DE"
109 + "\n --langfile=<file> used to specify an alternative language file\n");
111 // Initialise configuration if selected
114 if (configFilename != null) {
115 Config.loadFile(new File(configFilename));
118 Config.loadDefaultFile();
121 catch (ConfigException ce) {
122 System.err.println("Failed to load config file: " + configFilename);
124 boolean overrideLang = (locale != null);
126 // Make sure Config holds chosen language
127 Config.setConfigString(Config.KEY_LANGUAGE_CODE, localeCode);
130 // Set locale according to Config's language property
131 String configLang = Config.getConfigString(Config.KEY_LANGUAGE_CODE);
132 if (configLang != null) {
133 Locale configLocale = getLanguage(configLang);
134 if (configLocale != null) {locale = configLocale;}
137 I18nManager.init(locale);
138 // Load the external language file, either from config file or from command line params
139 if (langFilename == null && !overrideLang) {
140 // If langfilename is blank on command line parameters then don't use setting from config
141 langFilename = Config.getConfigString(Config.KEY_LANGUAGE_FILE);
143 if (langFilename != null)
146 I18nManager.addLanguageFile(langFilename);
147 Config.setConfigString(Config.KEY_LANGUAGE_FILE, langFilename);
149 catch (FileNotFoundException fnfe) {
150 System.err.println("Failed to load language file: " + langFilename);
151 Config.setConfigString(Config.KEY_LANGUAGE_FILE, "");
157 String windowStyle = Config.getConfigString(Config.KEY_WINDOW_STYLE);
158 UIManager.setLookAndFeel(windowStyle);
160 catch (Exception e) {}
162 // Set up the window and go
168 * Choose a locale based on the given code
169 * @param inString code for locale
170 * @return Locale object if available, otherwise null
172 private static Locale getLanguage(String inString)
174 if (inString.length() == 2)
176 return new Locale(inString);
178 else if (inString.length() == 5 && inString.charAt(2) == '_')
180 return new Locale(inString.substring(0, 2), inString.substring(3));
182 System.out.println("Unrecognised locale '" + inString
183 + "' - value should be eg 'DE' or 'DE_ch'");
189 * Launch the main application
190 * @param inDataFiles list of data files to load on startup
192 private static void launch(ArrayList<File> inDataFiles)
195 JFrame frame = new JFrame(PROGRAM_NAME);
196 APP = new App(frame);
199 MenuManager menuManager = new MenuManager(APP, APP.getTrackInfo());
200 frame.setJMenuBar(menuManager.createMenuBar());
201 APP.setMenuManager(menuManager);
202 UpdateMessageBroker.addSubscriber(menuManager);
203 // Make toolbar for buttons
204 JToolBar toolbar = menuManager.createToolBar();
206 // Make main GUI components and add as listeners
207 SelectorDisplay leftPanel = new SelectorDisplay(APP.getTrackInfo());
208 UpdateMessageBroker.addSubscriber(leftPanel);
209 DetailsDisplay rightPanel = new DetailsDisplay(APP.getTrackInfo());
210 UpdateMessageBroker.addSubscriber(rightPanel);
211 MapCanvas mapDisp = new MapCanvas(APP, APP.getTrackInfo());
212 UpdateMessageBroker.addSubscriber(mapDisp);
213 Viewport viewport = new Viewport(mapDisp);
214 APP.setViewport(viewport);
215 ProfileChart profileDisp = new ProfileChart(APP.getTrackInfo());
216 UpdateMessageBroker.addSubscriber(profileDisp);
217 StatusBar statusBar = new StatusBar();
218 UpdateMessageBroker.addSubscriber(statusBar);
219 UpdateMessageBroker.informSubscribers("GpsPrune v" + VERSION_NUMBER);
221 // Arrange in the frame using split panes
222 JSplitPane midSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, mapDisp, profileDisp);
223 midSplit.setResizeWeight(1.0); // allocate as much space as poss to map
224 JSplitPane rightSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, midSplit, rightPanel);
225 rightSplit.setResizeWeight(1.0); // allocate as much space as poss to map
227 frame.getContentPane().setLayout(new BorderLayout());
228 frame.getContentPane().add(toolbar, BorderLayout.NORTH);
229 JSplitPane leftSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rightSplit);
230 frame.getContentPane().add(leftSplit, BorderLayout.CENTER);
231 frame.getContentPane().add(statusBar, BorderLayout.SOUTH);
233 // add closing listener
234 frame.addWindowListener(new WindowAdapter() {
235 public void windowClosing(WindowEvent e) {
239 // Avoid automatically shutting down if window closed
240 frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
242 // set window icons of different resolutions (1.6+)
245 ArrayList<Image> icons = new ArrayList<Image>();
246 String[] resolutions = {"_16", "_20", "_22", "_24", "_32", "_36", "_48", "_64", "_72", "_96", "_128"};
247 for (String r : resolutions) {
248 icons.add(IconManager.getImageIcon(IconManager.WINDOW_ICON + r + ".png").getImage());
250 Class<?> d = java.awt.Window.class;
251 // This is the same as frame.setIconImages(icons) but is compilable also for java1.5 where this isn't available
252 d.getDeclaredMethod("setIconImages", new Class[]{java.util.List.class}).invoke(frame, icons);
256 // setting a list of icon images didn't work, so try with just one image instead
258 frame.setIconImage(IconManager.getImageIcon(IconManager.WINDOW_ICON + "_16.png").getImage());
260 catch (Exception e2) {}
263 // Set up drag-and-drop handler to accept dropped files
264 frame.setTransferHandler(new FileDropHandler(APP));
266 // finish off and display frame
268 if (!setFrameBoundsFromConfig(frame))
270 frame.setSize(650, 450);
272 frame.setVisible(true);
273 // Set position of map/profile splitter
274 midSplit.setDividerLocation(0.75);
275 // Update menu (only needed for recent file list)
276 UpdateMessageBroker.informSubscribers();
278 // Make a full screen toggler
279 SidebarController fsc = new SidebarController(new Component[] {leftPanel, profileDisp, rightPanel},
280 new JSplitPane[] {leftSplit, midSplit, rightSplit});
281 APP.setSidebarController(fsc);
282 // Finally, give the files to load to the App
283 APP.loadDataFiles(inDataFiles);
288 * Set the frame bounds using the saved config setting
289 * @param inFrame frame to set the bounds of
290 * @return true on success
292 private static boolean setFrameBoundsFromConfig(JFrame inFrame)
294 // Try to get bounds from config
295 String bounds = Config.getConfigString(Config.KEY_WINDOW_BOUNDS);
298 String[] boundValues = bounds.split("x");
299 if (boundValues.length == 4)
301 int[] elems = new int[4];
302 for (int i=0; i<4; i++) {
303 elems[i] = Integer.parseInt(boundValues[i]);
305 // Make sure width and height aren't stupid
306 elems[2] = Math.max(elems[2], 400);
307 elems[3] = Math.max(elems[3], 300);
308 inFrame.setBounds(elems[0], elems[1], elems[2], elems[3]);
312 catch (NullPointerException npe) {} // if no entry found in config
313 catch (NumberFormatException nfe) {} // if string couldn't be parsed
319 * Try to guess whether it's a mistyped parameter or a mistyped filename
320 * @param inParam command line argument
321 * @return error message
323 private static String makeUnknownParameterString(String inParam)
325 File file = new File(inParam);
328 if (file.isDirectory()) return "'" + inParam + "' is a directory";
329 if (!file.canRead()) return "Cannot read file '" + inParam + "'";
330 return "Something wrong with file '" + inParam + "'";
334 String name = file.getName();
335 file = file.getParentFile();
336 if (file != null && file.exists() && file.canRead()) return "Tried to load file '" + inParam + "' but cannot find '" + name + "'";
338 while (file != null);
340 return "Unknown parameter '" + inParam + "'";