source: josm/trunk/src/org/openstreetmap/josm/gui/MainFrame.java@ 18287

Last change on this file since 18287 was 18287, checked in by Don-vip, 4 years ago

fix #20913 - fix handling of GPX files in sessions (patch by Bjoeni)

  • revert r17659 (except for unit tests) - see #20233
    • don't save GPX track and marker colors in session file anymore, but in the GPX files as extensions (like before)
    • don't ask to save unmodified GPX file
    • don't override global color settings when individual track doesn't have a color
  • ask user to save changes to GPX file when any drawing settings or marker colors have changed (currently only happens for track colors)
  • save marker color values to session even when corresponding GPX layer has already been deleted
  • save alpha values for GPX marker colors
  • added explanation to the "overwrite GPX file" dialog
  • inform user if not all files referenced by the session file are saved yet
  • allow user to save all files that are not included in the *.jos/*.joz but are only referenced in the session file
  • display * next to GPX layers that need to be saved (move isDirty() logic from OsmDataLayer to AbstractModifiableLayer)
  • Property svn:eol-style set to native
File size: 9.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.BorderLayout;
7import java.awt.Component;
8import java.awt.ComponentOrientation;
9import java.awt.Image;
10import java.awt.Rectangle;
11import java.awt.Toolkit;
12import java.awt.event.ComponentEvent;
13import java.awt.event.ComponentListener;
14import java.awt.event.WindowAdapter;
15import java.awt.event.WindowEvent;
16import java.beans.PropertyChangeListener;
17import java.util.List;
18import java.util.Locale;
19import java.util.Objects;
20import java.util.stream.Collectors;
21import java.util.stream.Stream;
22
23import javax.swing.ImageIcon;
24import javax.swing.JFrame;
25import javax.swing.JPanel;
26
27import org.openstreetmap.josm.data.UserIdentityManager;
28import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer;
29import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
30import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener;
31import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
32import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
33import org.openstreetmap.josm.gui.layer.OsmDataLayer;
34import org.openstreetmap.josm.gui.layer.OsmDataLayer.LayerStateChangeListener;
35import org.openstreetmap.josm.gui.util.WindowGeometry;
36import org.openstreetmap.josm.spi.preferences.Config;
37import org.openstreetmap.josm.tools.ImageProvider;
38import org.openstreetmap.josm.tools.Logging;
39
40/**
41 * This is the JOSM main window. It updates it's title.
42 * @author Michael Zangl
43 * @since 10340
44 */
45public class MainFrame extends JFrame {
46 private final transient LayerStateChangeListener updateTitleOnLayerStateChange = (layer, newValue) -> onLayerChange(layer);
47
48 private final transient PropertyChangeListener updateTitleOnSaveChange = evt -> {
49 if (evt.getPropertyName().equals(AbstractModifiableLayer.REQUIRES_SAVE_TO_DISK_PROP)
50 || evt.getPropertyName().equals(OsmDataLayer.REQUIRES_UPLOAD_TO_SERVER_PROP)) {
51 AbstractModifiableLayer layer = (AbstractModifiableLayer) evt.getSource();
52 onLayerChange(layer);
53 }
54 };
55
56 protected transient WindowGeometry geometry;
57 protected int windowState = JFrame.NORMAL;
58 private final MainPanel panel;
59 private MainMenu menu;
60
61 /**
62 * Create a new main window.
63 */
64 public MainFrame() {
65 this(new WindowGeometry(new Rectangle(10, 10, 500, 500)));
66 }
67
68 /**
69 * Create a new main window. The parameter will be removed in the future.
70 * @param geometry The initial geometry to use.
71 * @since 12127
72 */
73 public MainFrame(WindowGeometry geometry) {
74 super();
75 this.geometry = geometry;
76 this.panel = new MainPanel(MainApplication.getLayerManager());
77 setContentPane(new JPanel(new BorderLayout()));
78 setComponentOrientation();
79 }
80
81 private void setComponentOrientation() {
82 ComponentOrientation orientation = ComponentOrientation.getOrientation(Locale.getDefault());
83 if (orientation == ComponentOrientation.RIGHT_TO_LEFT) {
84 Logging.info(tr("Setting component orientation to right-to-left"));
85 }
86 applyComponentOrientation(orientation);
87 }
88
89 /**
90 * Initializes the content of the window and get the current status panel.
91 */
92 public void initialize() {
93 menu = new MainMenu();
94 addComponentListener(new WindowPositionSizeListener());
95 addWindowStateListener(new WindowPositionSizeListener());
96
97 setJMenuBar(menu);
98 geometry.applySafe(this);
99 List<Image> l = Stream.of(
100 /* ICON */ "logo_16x16x32",
101 /* ICON */ "logo_16x16x8",
102 /* ICON */ "logo_32x32x32",
103 /* ICON */ "logo_32x32x8",
104 /* ICON */ "logo_48x48x32",
105 /* ICON */ "logo_48x48x8",
106 /* ICON */ "logo")
107 .map(ImageProvider::getIfAvailable)
108 .filter(Objects::nonNull)
109 .map(ImageIcon::getImage)
110 .collect(Collectors.toList());
111 setIconImages(l);
112 addWindowListener(new ExitWindowAdapter());
113 setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
114
115 // This listener is never removed, since the main frame exists forever.
116 MainApplication.getLayerManager().addActiveLayerChangeListener(e -> refreshTitle());
117 MainApplication.getLayerManager().addAndFireLayerChangeListener(new ManageLayerListeners());
118 UserIdentityManager.getInstance().addListener(this::refreshTitle);
119 Config.getPref().addKeyPreferenceChangeListener("draw.show-user", e -> refreshTitle());
120 refreshTitle();
121
122 getContentPane().add(panel, BorderLayout.CENTER);
123 menu.initialize();
124 }
125
126 /**
127 * Stores the current state of the main frame.
128 */
129 public void storeState() {
130 if (geometry != null) {
131 geometry.remember(WindowGeometry.PREF_KEY_GUI_GEOMETRY);
132 }
133 Config.getPref().putBoolean("gui.maximized", (windowState & JFrame.MAXIMIZED_BOTH) != 0);
134 }
135
136 /**
137 * Gets the main menu used for this window.
138 * @return The main menu.
139 * @throws IllegalStateException if the main frame has not been initialized yet
140 * @see #initialize
141 */
142 public MainMenu getMenu() {
143 if (menu == null) {
144 throw new IllegalStateException("Not initialized.");
145 }
146 return menu;
147 }
148
149 /**
150 * Gets the main panel.
151 * @return The main panel.
152 * @since 12125
153 */
154 public MainPanel getPanel() {
155 return panel;
156 }
157
158 /**
159 * Sets this frame to be maximized.
160 * @param maximized <code>true</code> if the window should be maximized.
161 */
162 public void setMaximized(boolean maximized) {
163 if (maximized) {
164 if (Toolkit.getDefaultToolkit().isFrameStateSupported(JFrame.MAXIMIZED_BOTH)) {
165 windowState = JFrame.MAXIMIZED_BOTH;
166 setExtendedState(windowState);
167 } else {
168 Logging.debug("Main window: maximizing not supported");
169 }
170 } else {
171 throw new UnsupportedOperationException("Unimplemented.");
172 }
173 }
174
175 /**
176 * Update the title of the window to reflect the current content.
177 */
178 public void refreshTitle() {
179 OsmDataLayer editLayer = MainApplication.getLayerManager().getEditLayer();
180 boolean dirty = editLayer != null && editLayer.isDirty();
181 String userInfo = UserIdentityManager.getInstance().getUserName();
182 if (userInfo != null && Config.getPref().getBoolean("draw.show-user", false))
183 userInfo = tr(" ({0})", "@" + userInfo);
184 else
185 userInfo = "";
186 setTitle((dirty ? "* " : "") + tr("Java OpenStreetMap Editor") + userInfo);
187 getRootPane().putClientProperty("Window.documentModified", dirty);
188 }
189
190 private void onLayerChange(AbstractModifiableLayer layer) {
191 if (layer == MainApplication.getLayerManager().getEditLayer()) {
192 refreshTitle();
193 }
194 }
195
196 static final class ExitWindowAdapter extends WindowAdapter {
197 @Override
198 public void windowClosing(final WindowEvent evt) {
199 MainApplication.exitJosm(true, 0, null);
200 }
201 }
202
203 /**
204 * Manages the layer listeners, adds them to every layer.
205 */
206 private final class ManageLayerListeners implements LayerChangeListener {
207 @Override
208 public void layerAdded(LayerAddEvent e) {
209 if (e.getAddedLayer() instanceof OsmDataLayer) {
210 OsmDataLayer osmDataLayer = (OsmDataLayer) e.getAddedLayer();
211 osmDataLayer.addLayerStateChangeListener(updateTitleOnLayerStateChange);
212 }
213 e.getAddedLayer().addPropertyChangeListener(updateTitleOnSaveChange);
214 }
215
216 @Override
217 public void layerRemoving(LayerRemoveEvent e) {
218 if (e.getRemovedLayer() instanceof OsmDataLayer) {
219 OsmDataLayer osmDataLayer = (OsmDataLayer) e.getRemovedLayer();
220 osmDataLayer.removeLayerStateChangeListener(updateTitleOnLayerStateChange);
221 }
222 e.getRemovedLayer().removePropertyChangeListener(updateTitleOnSaveChange);
223 }
224
225 @Override
226 public void layerOrderChanged(LayerOrderChangeEvent e) {
227 // not used
228 }
229 }
230
231 private class WindowPositionSizeListener extends WindowAdapter implements ComponentListener {
232 @Override
233 public void windowStateChanged(WindowEvent e) {
234 windowState = e.getNewState();
235 }
236
237 @Override
238 public void componentHidden(ComponentEvent e) {
239 // Do nothing
240 }
241
242 @Override
243 public void componentMoved(ComponentEvent e) {
244 handleComponentEvent(e);
245 }
246
247 @Override
248 public void componentResized(ComponentEvent e) {
249 handleComponentEvent(e);
250 }
251
252 @Override
253 public void componentShown(ComponentEvent e) {
254 // Do nothing
255 }
256
257 private void handleComponentEvent(ComponentEvent e) {
258 Component c = e.getComponent();
259 if (c instanceof JFrame && c.isVisible()) {
260 if (windowState == JFrame.NORMAL) {
261 geometry = new WindowGeometry((JFrame) c);
262 } else {
263 geometry.fixScreen((JFrame) c);
264 }
265 }
266 }
267 }
268
269}
Note: See TracBrowser for help on using the repository browser.