// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.gui; import java.awt.BorderLayout; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import javax.swing.JPanel; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.actions.mapmode.MapMode; import org.openstreetmap.josm.gui.layer.Layer; import org.openstreetmap.josm.gui.layer.MainLayerManager; import org.openstreetmap.josm.gui.layer.MainLayerManager.LayerAvailabilityEvent; import org.openstreetmap.josm.gui.layer.MainLayerManager.LayerAvailabilityListener; import org.openstreetmap.josm.gui.util.GuiHelper; /** * This is the content panel inside the {@link MainFrame}. It displays the content the user is working with. * <p> * If there is no active layer, there is no content displayed. As soon as there are active layers, the {@link MapFrame} is displayed. * * @author Michael Zangl * @since 10432 */ public class MainPanel extends JPanel { private MapFrame map; // Needs to be lazy because we need to wait for preferences to set up. private GettingStarted gettingStarted; private final CopyOnWriteArrayList<MapFrameListener> mapFrameListeners = new CopyOnWriteArrayList<>(); private final transient MainLayerManager layerManager; /** * Create a new main panel * @param layerManager The layer manager to use to display the content. */ public MainPanel(MainLayerManager layerManager) { super(new BorderLayout()); this.layerManager = layerManager; } /** * Update the content of this {@link MainFrame} to either display the map or display the welcome screen. * @param showMap If the map should be displayed. */ protected synchronized void updateContent(boolean showMap) { GuiHelper.assertCallFromEdt(); MapFrame old = map; if (old != null && showMap) { // no state change return; } // remove old content setVisible(false); removeAll(); if (old != null) { old.destroy(); } // create new content if (showMap) { map = createNewMapFrame(); } else { map = null; Main.map = map; add(getGettingStarted(), BorderLayout.CENTER); } setVisible(true); if (old == null && !showMap) { // listeners may not be able to handle this... return; } // Notify map frame listeners, mostly plugins. for (MapFrameListener listener : mapFrameListeners) { listener.mapFrameInitialized(old, map); } if (map == null && Main.currentProgressMonitor != null) { Main.currentProgressMonitor.showForegroundDialog(); } } private MapFrame createNewMapFrame() { MapFrame mapFrame = new MapFrame(null); // Required by many components. Main.map = mapFrame; mapFrame.fillPanel(this); //TODO: Move this to some better place List<Layer> layers = Main.getLayerManager().getLayers(); if (!layers.isEmpty()) { mapFrame.selectMapMode((MapMode) mapFrame.getDefaultButtonAction(), layers.get(0)); } mapFrame.initializeDialogsPane(); mapFrame.setVisible(true); return mapFrame; } /** * Registers a new {@code MapFrameListener} that will be notified of MapFrame changes. * <p> * It will fire an initial mapFrameInitialized event * when the MapFrame is present. Otherwise will only fire when the MapFrame is created * or destroyed. * @param listener The MapFrameListener * @return {@code true} if the listeners collection changed as a result of the call. */ public synchronized boolean addAndFireMapFrameListener(MapFrameListener listener) { boolean changed = addMapFrameListener(listener); if (changed && map != null) { listener.mapFrameInitialized(null, map); } return changed; } /** * Registers a new {@code MapFrameListener} that will be notified of MapFrame changes * @param listener The MapFrameListener * @return {@code true} if the listeners collection changed as a result of the call */ public boolean addMapFrameListener(MapFrameListener listener) { return listener != null && mapFrameListeners.add(listener); } /** * Unregisters the given {@code MapFrameListener} from MapFrame changes * @param listener The MapFrameListener * @return {@code true} if the listeners collection changed as a result of the call */ public boolean removeMapFrameListener(MapFrameListener listener) { return listener != null && mapFrameListeners.remove(listener); } /** * Gets the {@link GettingStarted} panel. * @return The panel. */ public synchronized GettingStarted getGettingStarted() { if (gettingStarted == null) { gettingStarted = new GettingStarted(); } return gettingStarted; } /** * Re-adds the layer listeners. Never call this in production, only needed for testing. */ public void reAddListeners() { layerManager.addLayerAvailabilityListener(new LayerAvailabilityListener() { @Override public void beforeFirstLayerAdded(LayerAvailabilityEvent e) { updateContent(true); } @Override public void afterLastLayerRemoved(LayerAvailabilityEvent e) { updateContent(false); } }); GuiHelper.runInEDTAndWait(() -> updateContent(!layerManager.getLayers().isEmpty())); } }