Gridarta Editor
MapDesktop.java
Go to the documentation of this file.
1 /*
2  * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
3  * Copyright (C) 2000-2015 The Gridarta Developers.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 package net.sf.gridarta.gui.mapdesktop;
21 
22 import java.beans.PropertyVetoException;
23 import java.util.IdentityHashMap;
24 import java.util.Iterator;
25 import java.util.Map;
26 import javax.swing.Action;
27 import javax.swing.Icon;
28 import javax.swing.ImageIcon;
29 import javax.swing.JDesktopPane;
30 import javax.swing.JInternalFrame;
31 import javax.swing.JMenu;
32 import javax.swing.event.InternalFrameEvent;
33 import javax.swing.event.InternalFrameListener;
47 import net.sf.japi.swing.action.ActionBuilder;
48 import net.sf.japi.swing.action.ActionBuilderFactory;
49 import net.sf.japi.swing.action.ActionMethod;
50 import org.apache.log4j.Category;
51 import org.apache.log4j.Logger;
52 import org.jetbrains.annotations.NotNull;
53 import org.jetbrains.annotations.Nullable;
54 
60 public class MapDesktop<G extends GameObject<G, A, R>, A extends MapArchObject<A>, R extends Archetype<G, A, R>> extends JDesktopPane implements EditorAction {
61 
65  @NotNull
66  private static final Category LOG = Logger.getLogger(MapDesktop.class);
67 
71  @NotNull
72  private static final ActionBuilder ACTION_BUILDER = ActionBuilderFactory.getInstance().getActionBuilder("net.sf.gridarta");
73 
77  private static final long serialVersionUID = 1L;
78 
82  @NotNull
84 
88  @NotNull
90 
94  @NotNull
96 
100  @NotNull
102 
106  @Nullable
107  private Action aPrevWindow;
108 
112  @Nullable
113  private Action aNextWindow;
114 
118  @NotNull
119  private final Map<MapView<G, A, R>, WindowAction<G, A, R>> windowActions = new IdentityHashMap<>();
120 
126  @NotNull
127  private final Map<MapView<G, A, R>, MapViewFrameListener> mapViewFrameListeners = new IdentityHashMap<>();
128 
132  @NotNull
134 
135  @Override
136  public void currentMapChanged(@Nullable final MapControl<G, A, R> mapControl) {
137  // ignore
138  }
139 
140  @Override
141  public void mapCreated(@NotNull final MapControl<G, A, R> mapControl, final boolean interactive) {
142  mapViewsManager.addMapViewsListener(mapControl, mapViewsListener);
143  }
144 
145  @Override
146  public void mapClosing(@NotNull final MapControl<G, A, R> mapControl) {
147  // ignore
148  }
149 
150  @Override
151  public void mapClosed(@NotNull final MapControl<G, A, R> mapControl) {
152  mapViewsManager.removeMapViewsListener(mapControl, mapViewsListener);
153  }
154 
155  };
156 
161  @NotNull
163 
164  @Override
165  public void mapViewCreated(@NotNull final MapView<G, A, R> mapView) {
166  addMapView(mapView);
167  }
168 
169  @Override
170  public void mapViewClosing(@NotNull final MapView<G, A, R> mapView) {
171  removeMapView(mapView);
172  }
173 
174  };
175 
179  @NotNull
181 
182  @Override
183  public void iconChanged(@NotNull final MapControl<G, A, R> mapControl) {
184  final Iterator<MapView<G, A, R>> it = mapViewsManager.getMapViewIterator(mapControl);
185  while (it.hasNext()) {
186  updateFrameIcon(it.next());
187  }
188  }
189 
190  };
191 
199  public MapDesktop(@NotNull final MapViewManager<G, A, R> mapViewManager, @NotNull final MapManager<G, A, R> mapManager, @NotNull final MapImageCache<G, A, R> mapImageCache, @NotNull final MapViewsManager<G, A, R> mapViewsManager) {
200  this.mapViewManager = mapViewManager;
201  this.mapManager = mapManager;
202  this.mapImageCache = mapImageCache;
203  this.mapViewsManager = mapViewsManager;
204  mapManager.addMapManagerListener(mapManagerListener);
205  mapImageCache.addMapImageCacheListener(mapImageCacheListener);
206  updateFocus(false);
207  }
208 
213  public void setCurrentMapView(@NotNull final MapView<G, A, R> mapView) {
214  mapViewManager.setActiveMapView(mapView);
215  // De-iconify if necessary
216  final JInternalFrame internalFrame = mapView.getInternalFrame();
217  if (internalFrame.isIcon()) {
218  try {
219  internalFrame.setIcon(false);
220  } catch (final PropertyVetoException e) {
221  LOG.warn(ACTION_BUILDER.format("logUnexpectedException", e));
222  }
223  mapView.activate();
224  return;
225  }
226  updateFocus(true);
227  internalFrame.requestFocus();
228  internalFrame.restoreSubcomponentFocus();
229  }
230 
235  private void removeMapView(@NotNull final MapView<G, A, R> mapView) {
236  final JInternalFrame internalFrame = mapView.getInternalFrame();
237  internalFrame.removeInternalFrameListener(mapViewFrameListeners.remove(mapView));
238  mapViewManager.removeMapView(mapView);
239  if (windowActions.remove(mapView) == null) {
240  assert false;
241  }
242  remove(internalFrame);
243  // This is important: Removing a JInternalFrame from a JDesktopPane doesn't deselect it.
244  // Thus it will still be referenced. To prevent a closed map from being referenced by Swing,
245  // we check whether it's selected and if so deselect it.
246  if (getSelectedFrame() == mapView) {
247  setSelectedFrame(null);
248  }
249  internalFrame.dispose();
250  repaint();
251 
252  updateFocus(true);
253  refreshMenus();
254  }
255 
260  private void addMapView(@NotNull final MapView<G, A, R> mapView) {
261  final WindowAction<G, A, R> windowAction = new WindowAction<>(this, mapView, mapManager);
262  windowActions.put(mapView, windowAction);
263  updateFrameIcon(mapView);
264 
265  final JInternalFrame internalFrame = mapView.getInternalFrame();
266  final MapViewFrameListener mapViewFrameListener = new MapViewFrameListener(mapView);
267  if (mapViewFrameListeners.put(mapView, mapViewFrameListener) != null) {
268  assert false;
269  }
270  internalFrame.addInternalFrameListener(mapViewFrameListener);
271  add(internalFrame);
272  mapViewManager.addMapView(mapView);
273  setCurrentMapView(mapView);
274  internalFrame.setVisible(true);
275  internalFrame.setBounds(0, 0, getWidth(), getHeight());
276  try {
277  internalFrame.setMaximum(true);
278  } catch (final PropertyVetoException e) {
279  LOG.error("PropertyVetoException: " + e);
280  }
281  refreshMenus();
282  }
283 
288  private void updateFrameIcon(@NotNull final MapView<G, A, R> mapView) {
289  final Action windowAction = windowActions.get(mapView);
290  assert windowAction != null;
291  final Icon icon = new ImageIcon(mapImageCache.getOrCreateIcon(mapView.getMapControl()));
292  mapView.getInternalFrame().setFrameIcon(icon);
293  windowAction.putValue(Action.SMALL_ICON, icon);
294  }
295 
302  public void addWindowAction(@NotNull final JMenu menu, @NotNull final MapView<G, A, R> mapView, final int index) {
303  final WindowAction<G, A, R> windowAction = windowActions.get(mapView);
304  assert windowAction != null;
305  windowAction.setIndex(index);
306  menu.add(windowAction);
307  }
308 
313  private void activateAndRaiseMapView(@NotNull final MapView<G, A, R> mapView) {
314  mapManager.setCurrentMap(mapView.getMapControl());
315  mapView.activate();
316  final JInternalFrame internalFrame = mapView.getInternalFrame();
317  internalFrame.moveToFront();
318  setSelectedFrame(internalFrame);
319  }
320 
326  private void mapViewFocusLostNotify(@NotNull final MapView<G, A, R> mapView) {
327  mapViewManager.deactivateMapView(mapView);
328  updateFocus(true);
329  }
330 
335  private void mapViewFocusGainedNotify(@NotNull final MapView<G, A, R> mapView) {
336  mapViewManager.activateMapView(mapView);
337  mapViewsManager.setFocus(mapView);
338  mapManager.setCurrentMap(mapView.getMapControl());
339  }
340 
346  private void updateFocus(final boolean careAboutIconification) {
347  // Show the next map (if such exists)
348  for (final MapView<G, A, R> mapView : mapViewManager) {
349  final JInternalFrame internalFrame = mapView.getInternalFrame();
350  if (internalFrame.isIcon()) {
351  if (!careAboutIconification) {
352  try {
353  internalFrame.setIcon(false);
354  } catch (final PropertyVetoException e) {
355  LOG.warn(ACTION_BUILDER.format("logUnexpectedException", e));
356  }
357  activateAndRaiseMapView(mapView);
358  return;
359  }
360  } else {
361  activateAndRaiseMapView(mapView);
362  return;
363  }
364  }
365 
366  // No non-iconified map windows found
367  mapManager.setCurrentMap(null);
368  }
369 
373  @ActionMethod
374  public void prevWindow() {
375  doPrevWindow(true);
376  }
377 
381  @ActionMethod
382  public void nextWindow() {
383  doNextWindow(true);
384  }
385 
389  private void refreshMenus() {
390  if (aPrevWindow != null) {
391  //noinspection ConstantConditions
392  aPrevWindow.setEnabled(doPrevWindow(false));
393  }
394  if (aNextWindow != null) {
395  //noinspection ConstantConditions
396  aNextWindow.setEnabled(doNextWindow(false));
397  }
398  }
399 
405  private boolean doPrevWindow(final boolean performAction) {
406  if (!mapViewManager.doPrevWindow(performAction)) {
407  return false;
408  }
409 
410  if (performAction) {
411  updateFocus(false);
412  }
413 
414  return true;
415  }
416 
422  private boolean doNextWindow(final boolean performAction) {
423  if (!mapViewManager.doNextWindow(performAction)) {
424  return false;
425  }
426 
427  if (performAction) {
428  updateFocus(false);
429  }
430 
431  return true;
432  }
433 
434  @Override
435  public void setAction(@NotNull final Action action, @NotNull final String name) {
436  if (name.equals("prevWindow")) {
437  aPrevWindow = action;
438  } else if (name.equals("nextWindow")) {
439  aNextWindow = action;
440  } else {
441  throw new IllegalArgumentException();
442  }
443  refreshMenus();
444  }
445 
449  private class MapViewFrameListener implements InternalFrameListener {
450 
454  @NotNull
455  private final MapView<G, A, R> mapView;
456 
461  private MapViewFrameListener(@NotNull final MapView<G, A, R> mapView) {
462  this.mapView = mapView;
463  }
464 
465  @Override
466  public void internalFrameActivated(@NotNull final InternalFrameEvent e) {
467  mapViewFocusGainedNotify(mapView);
468  }
469 
470  @Override
471  public void internalFrameClosed(@NotNull final InternalFrameEvent e) {
472  // ignore
473  }
474 
475  @Override
476  public void internalFrameClosing(@NotNull final InternalFrameEvent e) {
477  mapViewsManager.closeMapView(mapView);
478  }
479 
480  @Override
481  public void internalFrameDeactivated(@NotNull final InternalFrameEvent e) {
482  // ignore
483  }
484 
485  @Override
486  public void internalFrameDeiconified(@NotNull final InternalFrameEvent e) {
487  // ignore
488  }
489 
490  @Override
491  public void internalFrameIconified(@NotNull final InternalFrameEvent e) {
492  mapViewFocusLostNotify(mapView);
493  }
494 
495  @Override
496  public void internalFrameOpened(@NotNull final InternalFrameEvent e) {
497  // ignore
498  }
499 
500  }
501 
502 }
boolean doNextWindow(final boolean performAction)
Executes the "next window" action.
void addMapViewsListener(@NotNull final MapControl< G, A, R > mapControl, @NotNull final MapViewsListener< G, A, R > listener)
Adds a MapViewsListener to be notified of events.
void addMapView(@NotNull final MapView< G, A, R > mapView)
Adds a map view.
final MapManager< G, A, R > mapManager
The MapManager to use.
Definition: MapDesktop.java:89
Image getOrCreateIcon(@NotNull final File mapFile)
Returns an icon Image for a given map file.
void removeMapViewsListener(@NotNull final MapControl< G, A, R > mapControl, @NotNull final MapViewsListener< G, A, R > listener)
Removes a MapViewsListener to be notified of events.
void mapViewFocusGainedNotify(@NotNull final MapView< G, A, R > mapView)
Notifies that the given map view is now set as the current one.
A MapManager manages all opened maps.
Definition: MapManager.java:37
void closeMapView(@NotNull final MapView< G, A, R > mapView)
Invoked when the user wants to close a map view.
Graphical User Interface of Gridarta.
void internalFrameOpened(@NotNull final InternalFrameEvent e)
The JDesktopPane containing all map views.
Definition: MapDesktop.java:60
void removeMapView(@NotNull final MapView< G, A, R > mapView)
Removes (closes) the map view.
static final long serialVersionUID
The serial version UID.
Definition: MapDesktop.java:77
final MapViewsListener< G, A, R > mapViewsListener
The MapViewsListener attached to all existing MapControls for maps.
void internalFrameIconified(@NotNull final InternalFrameEvent e)
boolean doPrevWindow(final boolean performAction)
Executes the "prev window" action.
MapDesktop(@NotNull final MapViewManager< G, A, R > mapViewManager, @NotNull final MapManager< G, A, R > mapManager, @NotNull final MapImageCache< G, A, R > mapImageCache, @NotNull final MapViewsManager< G, A, R > mapViewsManager)
Creates a new instance.
void updateFrameIcon(@NotNull final MapView< G, A, R > mapView)
Updates the frame icon to the current icon image.
void internalFrameActivated(@NotNull final InternalFrameEvent e)
void internalFrameDeiconified(@NotNull final InternalFrameEvent e)
void nextWindow()
Gives focus to the previous window.
final Map< MapView< G, A, R >, MapViewFrameListener > mapViewFrameListeners
The MapViewFrameListeners associated with MapViews.
void prevWindow()
Gives focus to the next window.
void removeMapView(@NotNull final MapView< G, A, R > mapView)
Removes a map view.
void addMapView(@NotNull final MapView< G, A, R > mapView)
Adds the map view.
void addWindowAction(@NotNull final JMenu menu, @NotNull final MapView< G, A, R > mapView, final int index)
Adds an action for selecting this window to a menu.
Base package of all Gridarta classes.
Reflects a game object (object on a map).
Definition: GameObject.java:36
void internalFrameClosed(@NotNull final InternalFrameEvent e)
Action class for selecting this window.
A global editor action.
Interface for listeners listening to MapManager changes.
Action aPrevWindow
The action for "prev window".
Action aNextWindow
The action for "next window".
void activateAndRaiseMapView(@NotNull final MapView< G, A, R > mapView)
Activates and raises the given map view.
void mapViewFocusLostNotify(@NotNull final MapView< G, A, R > mapView)
Notifies that the map views focus is lost it is inserted as the second in line to the map view vector...
final MapImageCache< G, A, R > mapImageCache
The MapImageCache to use.
Definition: MapDesktop.java:95
void deactivateMapView(@NotNull final MapView< G, A, R > mapView)
Deactivates a map view.
GameObjects are the objects based on Archetypes found on maps.
void internalFrameClosing(@NotNull final InternalFrameEvent e)
void setActiveMapView(@NotNull final MapView< G, A, R > mapView)
Sets the active map view.
void setAction(@NotNull final Action action, @NotNull final String name)
Sets the Action instance for this editor action.
static final ActionBuilder ACTION_BUILDER
The action builder.
Definition: MapDesktop.java:72
Caches icon and preview images for map files.
final MapViewsManager< G, A, R > mapViewsManager
The MapViewsManager.
void refreshMenus()
Enables/disables the actions according to the current state.
Base classes for rendering maps.
boolean doNextWindow(final boolean performAction)
Performs or checks availability of the "next window" action.
final void setIndex(final int index)
Set the index of this action so this Action knows what Mnemonic and Accelerator to use...
void setCurrentMap(@Nullable MapControl< G, A, R > mapControl)
Sets the given map as the current one.
final Map< MapView< G, A, R >, WindowAction< G, A, R > > windowActions
The actions to select windows.
void updateFocus(final boolean careAboutIconification)
Updates the focus to the first non-iconified map window.
Interface for listeners interested in MapViewsManager related events.
final MapImageCacheListener< G, A, R > mapImageCacheListener
The MapImageCacheListener registered to mapImageCache.
void setCurrentMapView(@NotNull final MapView< G, A, R > mapView)
Sets the given level view as the current one.
final MapManagerListener< G, A, R > mapManagerListener
The MapManagerListener attached to mapManager.
final MapViewManager< G, A, R > mapViewManager
All open map views.
Definition: MapDesktop.java:83
Currently nothing more than a marker interface for unification.
Definition: MapControl.java:35
final MapView< G, A, R > mapView
The associated MapView.
A map view consists of a map grid and a map cursor, and is attached to a map control.
Definition: MapView.java:43
void internalFrameDeactivated(@NotNull final InternalFrameEvent e)
MapViewFrameListener(@NotNull final MapView< G, A, R > mapView)
Creates a new instance.
Interface for listeners interested in MapImageCache related events.
Iterator< MapView< G, A, R > > getMapViewIterator(@NotNull final MapControl< G, A, R > mapControl)
Returns an Iterator returning all MapViews of a MapControl.
boolean doPrevWindow(final boolean performAction)
Performs or checks availability of the "prev window" action.
static final Category LOG
The Logger for printing log messages.
Definition: MapDesktop.java:66
void activateMapView(@NotNull final MapView< G, A, R > mapView)
Activates a map view.
void setFocus(@NotNull final MapView< G, A, R > mapView)
Sets a MapView as the main view.