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

Last change on this file since 18069 was 17730, checked in by simon04, 3 years ago

see #16163 - MainApplication: apply component orientation based on locale

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