source: josm/src/org/openstreetmap/josm/Main.java@ 154

Last change on this file since 154 was 154, checked in by imi, 18 years ago
  • enhanced plugin system to integrate osmarender
File size: 14.8 KB
Line 
1package org.openstreetmap.josm;
2import static org.openstreetmap.josm.tools.I18n.tr;
3
4import java.awt.BorderLayout;
5import java.awt.Component;
6import java.awt.Dimension;
7import java.awt.Rectangle;
8import java.awt.Toolkit;
9import java.awt.event.ActionEvent;
10import java.io.File;
11import java.net.URI;
12import java.net.URISyntaxException;
13import java.util.Collection;
14import java.util.LinkedList;
15import java.util.Map;
16import java.util.StringTokenizer;
17import java.util.concurrent.Executor;
18import java.util.concurrent.Executors;
19import java.util.regex.Matcher;
20import java.util.regex.Pattern;
21
22import javax.swing.AbstractAction;
23import javax.swing.Action;
24import javax.swing.JMenu;
25import javax.swing.JMenuBar;
26import javax.swing.JOptionPane;
27import javax.swing.JPanel;
28import javax.swing.JSeparator;
29import javax.swing.JToolBar;
30import javax.swing.SwingUtilities;
31import javax.swing.UIManager;
32
33import org.openstreetmap.josm.actions.AboutAction;
34import org.openstreetmap.josm.actions.AlignInCircleAction;
35import org.openstreetmap.josm.actions.DownloadAction;
36import org.openstreetmap.josm.actions.ExitAction;
37import org.openstreetmap.josm.actions.ExternalToolsAction;
38import org.openstreetmap.josm.actions.GpxExportAction;
39import org.openstreetmap.josm.actions.OpenAction;
40import org.openstreetmap.josm.actions.PreferencesAction;
41import org.openstreetmap.josm.actions.RedoAction;
42import org.openstreetmap.josm.actions.ReverseSegmentAction;
43import org.openstreetmap.josm.actions.SaveAction;
44import org.openstreetmap.josm.actions.SaveAsAction;
45import org.openstreetmap.josm.actions.UndoAction;
46import org.openstreetmap.josm.actions.UploadAction;
47import org.openstreetmap.josm.actions.DownloadAction.DownloadTask;
48import org.openstreetmap.josm.actions.mapmode.MapMode;
49import org.openstreetmap.josm.data.Bounds;
50import org.openstreetmap.josm.data.Preferences;
51import org.openstreetmap.josm.data.osm.DataSet;
52import org.openstreetmap.josm.data.projection.Epsg4326;
53import org.openstreetmap.josm.data.projection.Projection;
54import org.openstreetmap.josm.gui.MapFrame;
55import org.openstreetmap.josm.gui.PleaseWaitDialog;
56import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
57import org.openstreetmap.josm.gui.annotation.AnnotationTester;
58import org.openstreetmap.josm.gui.dialogs.SelectionListDialog;
59import org.openstreetmap.josm.gui.layer.Layer;
60import org.openstreetmap.josm.gui.layer.OsmDataLayer;
61import org.openstreetmap.josm.gui.layer.OsmDataLayer.CommandQueueListener;
62import org.openstreetmap.josm.plugins.PluginException;
63import org.openstreetmap.josm.plugins.PluginInformation;
64import org.openstreetmap.josm.plugins.PluginProxy;
65import org.openstreetmap.josm.tools.ImageProvider;
66
67abstract public class Main {
68 /**
69 * Global parent component for all dialogs and message boxes
70 */
71 public static Component parent;
72 /**
73 * Global application window. Use this as JOPtionPane-parent to center on application.
74 */
75 public static Main main;
76 /**
77 * The worker thread slave. This is for executing all long and intensive
78 * calculations. The executed runnables are guaranteed to be executed seperatly
79 * and sequenciel.
80 */
81 public final static Executor worker = Executors.newSingleThreadExecutor();
82 /**
83 * Global application preferences
84 */
85 public static Preferences pref = new Preferences();
86 /**
87 * The global dataset.
88 */
89 public static DataSet ds = new DataSet();
90 /**
91 * The projection method used.
92 */
93 public static Projection proj;
94 /**
95 * The MapFrame. Use setMapFrame to set or clear it.
96 */
97 public static MapFrame map;
98 /**
99 * All installed and loaded plugins (resp. their main classes)
100 */
101 public final static Collection<PluginProxy> plugins = new LinkedList<PluginProxy>();
102 /**
103 * The dialog that gets displayed during background task execution.
104 */
105 public static PleaseWaitDialog pleaseWaitDlg;
106
107
108 /**
109 * Set or clear (if passed <code>null</code>) the map.
110 */
111 public final void setMapFrame(final MapFrame map) {
112 MapFrame old = Main.map;
113 Main.map = map;
114 panel.setVisible(false);
115 panel.removeAll();
116 if (map != null) {
117 map.fillPanel(panel);
118 panel.setVisible(true);
119 map.mapView.addLayerChangeListener(new LayerChangeListener(){
120 public void activeLayerChange(final Layer oldLayer, final Layer newLayer) {
121 setLayerMenu(newLayer.getMenuEntries());
122 }
123 public void layerAdded(final Layer newLayer) {
124 if (newLayer instanceof OsmDataLayer)
125 Main.main.editLayer().listenerCommands.add(redoUndoListener);
126 }
127 public void layerRemoved(final Layer oldLayer) {
128 if (oldLayer instanceof OsmDataLayer)
129 Main.main.editLayer().listenerCommands.add(redoUndoListener);
130 if (map.mapView.getAllLayers().isEmpty())
131 setLayerMenu(null);
132 }
133 });
134 if (map.mapView.editLayer != null)
135 map.mapView.editLayer.listenerCommands.add(redoUndoListener);
136 }
137 redoUndoListener.commandChanged(0,0);
138
139 for (PluginProxy plugin : plugins)
140 plugin.mapFrameInitialized(old, map);
141 }
142
143 /**
144 * Set the layer menu (changed when active layer changes).
145 */
146 public final void setLayerMenu(Component[] entries) {
147 if (entries == null || entries.length == 0)
148 layerMenu.setVisible(false);
149 else {
150 layerMenu.removeAll();
151 for (Component c : entries)
152 layerMenu.add(c);
153 layerMenu.setVisible(true);
154 }
155 }
156
157 /**
158 * Remove the specified layer from the map. If it is the last layer, remove the map as well.
159 */
160 public final void removeLayer(final Layer layer) {
161 map.mapView.removeLayer(layer);
162 if (layer instanceof OsmDataLayer)
163 ds = new DataSet();
164 if (map.mapView.getAllLayers().isEmpty())
165 setMapFrame(null);
166 }
167
168
169 public Main() {
170 main = this;
171 contentPane.add(panel, BorderLayout.CENTER);
172
173 final Action annotationTesterAction = new AbstractAction(){
174 public void actionPerformed(ActionEvent e) {
175 String annotationSources = pref.get("annotation.sources");
176 if (annotationSources.equals("")) {
177 JOptionPane.showMessageDialog(Main.parent, tr("You have to specify annotation sources in the preferences first."));
178 return;
179 }
180 String[] args = annotationSources.split(";");
181 new AnnotationTester(args);
182 }
183 };
184 annotationTesterAction.putValue(Action.NAME, tr("Annotation Preset Tester"));
185 annotationTesterAction.putValue(Action.SMALL_ICON, ImageProvider.get("annotation-tester"));
186 final Action reverseSegmentAction = new ReverseSegmentAction();
187 final Action alignInCircleAction = new AlignInCircleAction();
188 final Action uploadAction = new UploadAction();
189 final Action saveAction = new SaveAction();
190 final Action saveAsAction = new SaveAsAction();
191 final Action gpxExportAction = new GpxExportAction(null);
192 final Action exitAction = new ExitAction();
193 final Action preferencesAction = new PreferencesAction();
194 final Action aboutAction = new AboutAction();
195
196 final JMenu fileMenu = new JMenu(tr("Files"));
197 fileMenu.setMnemonic('F');
198 fileMenu.add(openAction);
199 fileMenu.add(saveAction);
200 fileMenu.add(saveAsAction);
201 fileMenu.add(gpxExportAction);
202 fileMenu.addSeparator();
203 fileMenu.add(exitAction);
204 mainMenu.add(fileMenu);
205
206
207 final JMenu connectionMenu = new JMenu(tr("Connection"));
208 connectionMenu.setMnemonic('C');
209 connectionMenu.add(downloadAction);
210 //connectionMenu.add(new DownloadIncompleteAction());
211 connectionMenu.add(uploadAction);
212 mainMenu.add(connectionMenu);
213
214 layerMenu = new JMenu(tr("Layer"));
215 layerMenu.setMnemonic('L');
216 mainMenu.add(layerMenu);
217 layerMenu.setVisible(false);
218
219 final JMenu editMenu = new JMenu(tr("Edit"));
220 editMenu.setMnemonic('E');
221 editMenu.add(undoAction);
222 editMenu.add(redoAction);
223 editMenu.addSeparator();
224 editMenu.add(reverseSegmentAction);
225 editMenu.add(alignInCircleAction);
226 editMenu.addSeparator();
227 editMenu.add(preferencesAction);
228 mainMenu.add(editMenu);
229
230 JMenu externalMenu = ExternalToolsAction.buildMenu();
231 if (externalMenu != null)
232 mainMenu.add(externalMenu);
233
234 mainMenu.add(new JSeparator());
235 final JMenu helpMenu = new JMenu(tr("Help"));
236 helpMenu.setMnemonic('H');
237 helpMenu.add(annotationTesterAction);
238 helpMenu.addSeparator();
239 helpMenu.add(aboutAction);
240 mainMenu.add(helpMenu);
241
242 // creating toolbar
243 final JToolBar toolBar = new JToolBar();
244 toolBar.setFloatable(false);
245 toolBar.add(downloadAction);
246 toolBar.add(uploadAction);
247 toolBar.addSeparator();
248 toolBar.add(openAction);
249 toolBar.add(saveAction);
250 toolBar.add(gpxExportAction);
251 toolBar.addSeparator();
252 toolBar.add(undoAction);
253 toolBar.add(redoAction);
254 toolBar.addSeparator();
255 toolBar.add(preferencesAction);
256 contentPane.add(toolBar, BorderLayout.NORTH);
257
258 contentPane.updateUI();
259
260 // Plugins
261 if (Main.pref.hasKey("plugins")) {
262 for (String pluginName : Main.pref.get("plugins").split(",")) {
263 try {
264 File pluginFile = new File(pref.getPreferencesDir()+"plugins/"+pluginName+".jar");
265 if (pluginFile.exists())
266 plugins.add(new PluginInformation(pluginFile).load());
267 else
268 JOptionPane.showMessageDialog(Main.parent, tr("Plugin not found: {0}.", pluginName));
269 } catch (PluginException e) {
270 e.printStackTrace();
271 JOptionPane.showMessageDialog(Main.parent, tr("Could not load plugin {0}.", pluginName));
272 }
273 }
274 }
275
276 SwingUtilities.updateComponentTreeUI(parent);
277 for (DownloadTask task : downloadAction.downloadTasks)
278 task.getCheckBox().updateUI();
279 }
280
281 /**
282 * Add a new layer to the map. If no map exist, create one.
283 */
284 public final void addLayer(final Layer layer) {
285 if (map == null) {
286 final MapFrame mapFrame = new MapFrame();
287 setMapFrame(mapFrame);
288 mapFrame.selectMapMode((MapMode)mapFrame.getDefaultButtonAction());
289 mapFrame.setVisible(true);
290 mapFrame.setVisibleDialogs();
291 }
292 map.mapView.addLayer(layer);
293 }
294 /**
295 * @return The edit osm layer. If none exist, it will be created.
296 */
297 public final OsmDataLayer editLayer() {
298 if (map == null || map.mapView.editLayer == null)
299 addLayer(new OsmDataLayer(ds, tr("unnamed"), null));
300 return map.mapView.editLayer;
301 }
302
303
304
305
306 /**
307 * Use this to register shortcuts to
308 */
309 public static final JPanel contentPane = new JPanel(new BorderLayout());
310
311
312 ////////////////////////////////////////////////////////////////////////////////////////
313 // Implementation part
314 ////////////////////////////////////////////////////////////////////////////////////////
315
316
317 public static JPanel panel = new JPanel(new BorderLayout());
318
319 public final JMenuBar mainMenu = new JMenuBar();
320 protected static Rectangle bounds;
321
322 public final UndoAction undoAction = new UndoAction();
323 public final RedoAction redoAction = new RedoAction();
324 public final OpenAction openAction = new OpenAction();
325 public final DownloadAction downloadAction = new DownloadAction();
326
327 private final CommandQueueListener redoUndoListener = new CommandQueueListener(){
328 public void commandChanged(final int queueSize, final int redoSize) {
329 undoAction.setEnabled(queueSize > 0);
330 redoAction.setEnabled(redoSize > 0);
331 }
332 };
333 private JMenu layerMenu;
334
335 /**
336 * Should be called before the main constructor to setup some parameter stuff
337 * @param args The parsed argument list.
338 */
339 public static void preConstructorInit(Map<String, Collection<String>> args) {
340 try {
341 Main.pref.upgrade(Integer.parseInt(AboutAction.version));
342 } catch (NumberFormatException e1) {
343 }
344
345 try {
346 Main.proj = (Projection)Class.forName(Main.pref.get("projection")).newInstance();
347 } catch (final Exception e) {
348 e.printStackTrace();
349 JOptionPane.showMessageDialog(null, tr("The projection could not be read from preferences. Using EPSG:4263."));
350 Main.proj = new Epsg4326();
351 }
352
353 try {
354 UIManager.setLookAndFeel(Main.pref.get("laf"));
355 contentPane.updateUI();
356 panel.updateUI();
357 } catch (final Exception e) {
358 e.printStackTrace();
359 }
360 UIManager.put("OptionPane.okIcon", ImageProvider.get("ok"));
361 UIManager.put("OptionPane.yesIcon", UIManager.get("OptionPane.okIcon"));
362 UIManager.put("OptionPane.cancelIcon", ImageProvider.get("cancel"));
363 UIManager.put("OptionPane.noIcon", UIManager.get("OptionPane.cancelIcon"));
364
365 Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
366 if (args.containsKey("geometry")) {
367 String geometry = args.get("geometry").iterator().next();
368 final Matcher m = Pattern.compile("(\\d+)x(\\d+)(([+-])(\\d+)([+-])(\\d+))?").matcher(geometry);
369 if (m.matches()) {
370 int w = Integer.valueOf(m.group(1));
371 int h = Integer.valueOf(m.group(2));
372 int x = 0, y = 0;
373 if (m.group(3) != null) {
374 x = Integer.valueOf(m.group(5));
375 y = Integer.valueOf(m.group(7));
376 if (m.group(4).equals("-"))
377 x = screenDimension.width - x - w;
378 if (m.group(6).equals("-"))
379 y = screenDimension.height - y - h;
380 }
381 bounds = new Rectangle(x,y,w,h);
382 } else
383 System.out.println("Ignoring malformed geometry: "+geometry);
384 }
385 if (bounds == null)
386 bounds = !args.containsKey("no-fullscreen") ? new Rectangle(0,0,screenDimension.width,screenDimension.height) : new Rectangle(1000,740);
387
388 pleaseWaitDlg = new PleaseWaitDialog();
389 }
390
391 public void postConstructorProcessCmdLine(Map<String, Collection<String>> args) {
392 if (args.containsKey("download"))
393 for (String s : args.get("download"))
394 downloadFromParamString(false, s);
395 if (args.containsKey("downloadgps"))
396 for (String s : args.get("downloadgps"))
397 downloadFromParamString(true, s);
398 if (args.containsKey("selection"))
399 for (String s : args.get("selection"))
400 SelectionListDialog.search(s, SelectionListDialog.SearchMode.add);
401 }
402
403 private static void downloadFromParamString(final boolean rawGps, String s) {
404 if (s.startsWith("http:")) {
405 final Bounds b = DownloadAction.osmurl2bounds(s);
406 if (b == null)
407 JOptionPane.showMessageDialog(Main.parent, tr("Ignoring malformed url: \"{0}\"", s));
408 else {
409 DownloadTask osmTask = main.downloadAction.downloadTasks.get(0);
410 osmTask.download(main.downloadAction, b.min.lat(), b.min.lon(), b.max.lat(), b.max.lon());
411 }
412 return;
413 }
414
415 if (s.startsWith("file:")) {
416 try {
417 main.openAction.openFile(new File(new URI(s)));
418 } catch (URISyntaxException e) {
419 JOptionPane.showMessageDialog(Main.parent, tr("Ignoring malformed file url: \"{0}\"", s));
420 }
421 return;
422 }
423
424 final StringTokenizer st = new StringTokenizer(s, ",");
425 if (st.countTokens() == 4) {
426 try {
427 DownloadTask task = main.downloadAction.downloadTasks.get(rawGps ? 1 : 0);
428 task.download(main.downloadAction, Double.parseDouble(st.nextToken()), Double.parseDouble(st.nextToken()), Double.parseDouble(st.nextToken()), Double.parseDouble(st.nextToken()));
429 return;
430 } catch (final NumberFormatException e) {
431 }
432 }
433
434 main.openAction.openFile(new File(s));
435 }
436}
Note: See TracBrowser for help on using the repository browser.