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