/******************************************************************************* * Copyright (c) 2010 Stefan A. Tzeggai. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v2.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * * Contributors: * Stefan A. Tzeggai - initial API and implementation ******************************************************************************/ package org.geopublishing.geopublisher.gui.map; import java.awt.Color; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.util.ArrayList; import java.util.List; import javax.swing.AbstractAction; import javax.swing.ImageIcon; import javax.swing.JCheckBoxMenuItem; import javax.swing.JDialog; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import org.apache.log4j.Logger; import org.geopublishing.atlasViewer.ExportableLayer; import org.geopublishing.atlasViewer.dp.DataPool.EventTypes; import org.geopublishing.atlasViewer.dp.layer.DpLayer; import org.geopublishing.atlasViewer.dp.layer.DpLayerVectorFeatureSource; import org.geopublishing.atlasViewer.dp.layer.LayerStyle; import org.geopublishing.atlasViewer.map.Map; import org.geopublishing.atlasViewer.swing.AtlasMapLayerLegend; import org.geopublishing.atlasViewer.swing.Icons; import org.geopublishing.atlasViewer.swing.MapLayerLegend; import org.geopublishing.geopublisher.AtlasConfigEditable; import org.geopublishing.geopublisher.gui.DesignAtlasStylerDialog; import org.geopublishing.geopublisher.gui.datapool.DataPoolJTable; import org.geopublishing.geopublisher.gui.internal.GPDialogManager; import org.geopublishing.geopublisher.swing.GeopublisherGUI; import org.geopublishing.geopublisher.swing.GpSwingUtil; import org.geotools.data.FeatureSource; import org.geotools.feature.FeatureCollection; import org.geotools.map.FeatureLayer; import org.geotools.map.MapLayer; import org.geotools.styling.Style; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import de.schmitzm.geotools.feature.FeatureUtil; import de.schmitzm.geotools.gui.FeatureLayerFilterDialog; import de.schmitzm.geotools.gui.MapView; import de.schmitzm.geotools.styling.StyledLayerUtil; import de.schmitzm.geotools.styling.StyledRasterInterface; import de.schmitzm.i18n.I18NUtil; import de.schmitzm.jfree.chart.style.ChartStyle; import de.schmitzm.swing.SwingUtil; /** * This extension of the basic {@link MapLayerLegend} introduces menu items and * behaviour which are only available in the {@link GeopublisherGUI} context. * * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a> */ public class DesignAtlasMapLayerLegend extends AtlasMapLayerLegend { protected Logger LOGGER = Logger.getLogger(DesignAtlasMapLayerLegend.class); protected AtlasConfigEditable ace; protected final DesignAtlasMapLegend mapLegend; private Color backup; /** * Returns <code>null</code> or a tooltip for the legend. The tool-tip does * not start/end with a <code>html</code> tag. That is added later. */ @Override public String getLegendTooltip() { if (dpLayer == null) return null; String tt = super.getLegendTooltip(); String newtt = ""; if (dpLayer.isBroken()) { newtt += "ERROR: " + dpLayer.getBrokenException().getLocalizedMessage(); } if (!hasVisibleAttributes() && (getLayer() instanceof FeatureLayer)) { newtt += "<b>∗</b> <b>" + GeopublisherGUI .R("DesignAtlasMapLayer.TT.layerHasNoVisibleAttribute") + "</b><br/>"; } if (isHiddenInLegend()) { newtt += "<b>∗</b> " + GeopublisherGUI .R("DesignAtlasMapLayer.TT.layerWillbeHiddenInAtlasLegend") + "<br/>"; } if (map.isSelectableFor(dpLayer.getId())) { newtt += "<font color='green'><b>∗</b> " + GeopublisherGUI .R("DesignAtlasMapLayer.TT.layerSelectable") + "</font><br/>"; } else { newtt += "<font color='red'><b>∗</b> " + GeopublisherGUI .R("DesignAtlasMapLayer.TT.layerNotSelectable") + "</font><br/>"; } return newtt + "<hr/>" + tt; } /** * This extension of the basic {@link MapLayerLegend} introduces menu items * and behavior which are only available in Geopublisher. * * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a> * @param map * Map that this */ public DesignAtlasMapLayerLegend(final MapLayer mapLayer, ExportableLayer exportable, DesignAtlasMapLegend mapLegend_, DpLayer<?, ChartStyle> dpLayer, Map map) { super(mapLayer, exportable, mapLegend_, dpLayer, map); this.mapLegend = mapLegend_; // this.atlasLayerPanel = mapLegend_; this.ace = mapLegend.getAce(); updateHiddenInLegendAppearance(); addMouseListener(listenToClicksAndSelectinDatapool); } /** * This MouseListener selects the clicked layers in the * {@link DataPoolJTable}. */ final MouseAdapter listenToClicksAndSelectinDatapool = new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { final DataPoolJTable dpJTable = GeopublisherGUI.getInstance() .getJFrame().getDatapoolJTable(); dpJTable.select(getMapLayer().getTitle()); } }; /** * If this layer would be hidden in a normal {@link AtlasMapLayerLegend}, we * give it a gray backgroung; * * @param id */ private void updateHiddenInLegendAppearance() { if (backup == null) backup = getForeground(); if (map.getHideInLegendFor(dpLayer.getId())) { setForeground(Color.white.darker()); } else { setForeground(backup); } } /** * @return <code>true</code> if the Datatable for this layer may be viewed * from within the AV. */ @Override public boolean isTableViewable() { return super.isTableViewable() && dpLayer.isTableVisibleInLegend(); } /** * @return <code>true</code> if the {@link Style} is possible to be edited * with the AS from the legend's tool menu. */ @Override public boolean isStyleEditable() { final boolean rasterStylable = styledLayer instanceof StyledRasterInterface && StyledLayerUtil .isStyleable((StyledRasterInterface<?>) styledLayer); final boolean featureStylable = FeatureUtil .getWrappedGeoObject((FeatureSource<SimpleFeatureType, SimpleFeature>) getMapLayer() .getFeatureSource()) instanceof FeatureCollection; // LOGGER.debug("rasterStylable = " + rasterStylable); return featureStylable || rasterStylable; } /** * @return <code>true</code> if the {@link MapLayer} is possible to be * filtered with {@link FeatureLayerFilterDialog} */ @Override public boolean isFilterable() { final MapLayer mapLayer = getMapLayer(); // final FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = (FeatureSource<SimpleFeatureType, SimpleFeature>) mapLayer // .getFeatureSource(); boolean hasFeatures = getMapLayer().getFeatureSource() != null; boolean hasVisibleAttributes = hasVisibleAttributes(); return hasFeatures && hasVisibleAttributes; // return JMapPane.getLayerSourceObject(mapLayer) instanceof // FeatureCollection; } @Override public JPopupMenu getToolMenu() { JPopupMenu menu = super.getToolMenu(); menu.addSeparator(); /** * Edit DPE */ menu.add(new AbstractAction(GeopublisherGUI .R("DataPoolWindow_Action_EditDPE_label"), Icons.ICON_TOOL) { @Override public void actionPerformed(ActionEvent e) { GPDialogManager.dm_EditDpEntry.getInstanceFor(dpLayer, mapLegend, styledLayer); } }); /* * Edit HTML .. */ menu.add(new AbstractAction(GeopublisherGUI .R("DataPoolWindow_Action_EditDPEHTML_label")) { @Override public void actionPerformed(ActionEvent e) { Window owner = SwingUtil .getParentWindow(DesignAtlasMapLayerLegend.this); List<File> infoFiles = GpSwingUtil.getHTMLFilesFor(dpLayer); ArrayList<String> tabTitles = new ArrayList<String>(); for (String l : ace.getLanguages()) { tabTitles.add(GeopublisherGUI.R( "EditLayerHTML.Tabs.Titles", I18NUtil .getFirstLocaleForLang(l) .getDisplayLanguage())); } final String dialogTitle = GeopublisherGUI.R( "EditLayerHTML.Dialog.Title", dpLayer.getTitle() .toString()); // GpSwingUtil.openHTMLEditors(owner, ace, infoFiles, tabTitles, // dialogTitle); String key = GpSwingUtil.openHTMLEditorsKey(infoFiles); Window instanceFor = GPDialogManager.dm_HtmlEditor .getInstanceFor(key, owner, ace, infoFiles, tabTitles, dialogTitle); // TODO In case this HTML editor is beeing tried to be opened // twice, these listeneras are added twice.! instanceFor.addWindowListener(new WindowAdapter() { @Override public void windowClosed(WindowEvent e) { super.windowClosed(e); /** * Try to update a few cached values for the TODO nicer! */ dpLayer.uncache(); ace.getDataPool() .fireChangeEvents(EventTypes.changeDpe); }; }); } }); /* * Delete all HTML files... */ final int countExisting = map.getAc().getLanguages().size() - dpLayer.getMissingHTMLLanguages().size(); if (countExisting > 0) { menu.add(new AbstractAction(GeopublisherGUI.R( "DataPoolWindow_Action_DeleteAllDPEHTML_label", countExisting), Icons.ICON_REMOVE) { @Override public void actionPerformed(ActionEvent e) { Window owner = SwingUtil .getParentWindow(DesignAtlasMapLayerLegend.this); SwingUtil.askYesNo(owner, GeopublisherGUI.R( "DataPoolWindow_Action_DeleteAllDPEHTML_Question", countExisting)); List<File> infoFiles = GpSwingUtil.getHTMLFilesFor(dpLayer); // TODO Delete image directory? NO! for (File f : infoFiles) { f.delete(); } /** * Try to update a few cached values for .. TODO nicer! */ dpLayer.uncache(); ace.getDataPool().fireChangeEvents(EventTypes.changeDpe); } }); } /* * The menu items to manage available styles and available charts are * valid on DpLayerVectorFeatureSource */ if (dpLayer instanceof DpLayerVectorFeatureSource) { final DpLayerVectorFeatureSource dplv = (DpLayerVectorFeatureSource) dpLayer; menu.addSeparator(); /** * Menu item: Manage available Charts for this layer in this map */ JMenuItem itemManageCharts = new JMenuItem(Icons.ICON_CHART_SMALL); itemManageCharts.setText(GeopublisherGUI .R("DataPoolWindow_Action_ManageCharts_label")); itemManageCharts.setToolTipText(GeopublisherGUI .R("DataPoolWindow_Action_ManageCharts_tt")); itemManageCharts.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { GPDialogManager.dm_ManageCharts.getInstanceFor(dplv, DesignAtlasMapLayerLegend.this, dplv, mapLegend); } }); itemManageCharts.setEnabled(hasVisibleAttributes()); menu.add(itemManageCharts); } /* * Menuitem: Manage Available Styles for this layer in this map */ JMenuItem itemManageViews = new JMenuItem(); itemManageViews.setText(GeopublisherGUI .R("DataPoolWindow_Action_ManageLayerStyles_label")); itemManageViews.setToolTipText(GeopublisherGUI .R("DataPoolWindow_Action_ManageLayerStyles_tt")); itemManageViews.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { getManageLayerStylesForMapDialog().setVisible(true); // atlasMapLegend.updateLegendIcon(styledLayer); atlasMapLegend.recreateLayerList(getMapLayer().getTitle()); } private JDialog getManageLayerStylesForMapDialog() { Style styleUsedRightNow = getMapLayer().getStyle(); ManageLayerStylesForMapDialog dialog = new ManageLayerStylesForMapDialog( DesignAtlasMapLayerLegend.this, dpLayer, ace, atlasMapLegend.getMap(), styleUsedRightNow, mapLegend); SwingUtil.centerFrameOnScreenRandom(dialog); return dialog; } }); menu.add(itemManageViews); /* * A separator to all the on/off checkboxes */ menu.addSeparator(); /* * Add a new MenuItem, to switch "hideInLegend" on/off */ JCheckBoxMenuItem hideOnOff = new JCheckBoxMenuItem(new AbstractAction( GeopublisherGUI.R("LayerToolMenu.hideInLegend")) { @Override public void actionPerformed(ActionEvent e) { JCheckBoxMenuItem checkBoxMenuItem = (JCheckBoxMenuItem) e .getSource(); getMap().getHideInLegendMap().put(dpLayer.getId(), checkBoxMenuItem.isSelected()); updateHiddenInLegendAppearance(); } }); Boolean hideThis = getMap().getHideInLegendMap().get(dpLayer.getId()); hideOnOff.setSelected(getMap().getHideInLegendMap() .get(dpLayer.getId()) == null ? false : hideThis); menu.add(hideOnOff); /* * Add a new MenuItem, to switch "showTableInLegend" on/off */ JCheckBoxMenuItem showTableInLegendOnOff = new JCheckBoxMenuItem( new AbstractAction( GeopublisherGUI.R("LayerToolMenu.showTableInLegend")) { @Override public void actionPerformed(ActionEvent e) { JCheckBoxMenuItem checkBoxMenuItem = (JCheckBoxMenuItem) e .getSource(); dpLayer.setTableInLegend(checkBoxMenuItem.isSelected() && hasVisibleAttributes()); } }); showTableInLegendOnOff.setSelected(dpLayer.isTableVisibleInLegend()); showTableInLegendOnOff.setEnabled(hasVisibleAttributes()); menu.add(showTableInLegendOnOff); /* * Add a new MenuItem, to switch "showFilterInLegend" on/off */ JCheckBoxMenuItem showFilterInLegendOnOff = new JCheckBoxMenuItem( new AbstractAction( GeopublisherGUI.R("LayerToolMenu.showFilterInLegend")) { @Override public void actionPerformed(ActionEvent e) { JCheckBoxMenuItem checkBoxMenuItem = (JCheckBoxMenuItem) e .getSource(); dpLayer.setFilterInLegend(checkBoxMenuItem.isSelected() && hasVisibleAttributes()); } }); showFilterInLegendOnOff.setSelected(dpLayer.isFilterInLegend()); showFilterInLegendOnOff.setEnabled(hasVisibleAttributes()); menu.add(showFilterInLegendOnOff); /** * Add a new MenuItem, to switch "showStylerInLegend" on/off */ JCheckBoxMenuItem showStylerInLegendOnOff = new JCheckBoxMenuItem( new AbstractAction( GeopublisherGUI.R("LayerToolMenu.showStylerInLegend")) { @Override public void actionPerformed(ActionEvent e) { JCheckBoxMenuItem checkBoxMenuItem = (JCheckBoxMenuItem) e .getSource(); dpLayer.setStylerInLegend(checkBoxMenuItem.isSelected()); } }); showStylerInLegendOnOff.setSelected(dpLayer.isStylerInLegend()); menu.add(showStylerInLegendOnOff); /** * Add a new MenuItem, to switch "exportable" on/off */ JCheckBoxMenuItem allowExportOnOff = new JCheckBoxMenuItem( // i8n new AbstractAction( GeopublisherGUI.R("EditDPEDialog.IsDpeExportable")) { @Override public void actionPerformed(ActionEvent e) { JCheckBoxMenuItem checkBoxMenuItem = (JCheckBoxMenuItem) e .getSource(); dpLayer.setExportable(checkBoxMenuItem.isSelected()); } }); allowExportOnOff.setSelected(dpLayer.isExportable()); menu.add(allowExportOnOff); /** * Add a new MenuItem, to switch "anklickbar" on/off */ JCheckBoxMenuItem layerSelectable = new JCheckBoxMenuItem( new AbstractAction( GeopublisherGUI.R("LayerToolMenu.selectable")) { @Override public void actionPerformed(ActionEvent e) { JCheckBoxMenuItem checkBoxMenuItem = (JCheckBoxMenuItem) e .getSource(); map.setSelectableFor(styledLayer.getId(), checkBoxMenuItem.isSelected()); mapLegend .getGeoMapPane() .getMapPane() .setMapLayerSelectable( getMapLayer(), checkBoxMenuItem.isSelected() && hasVisibleAttributesOrIsGrid()); } }); layerSelectable.setIcon(new ImageIcon(MapView.class .getResource("resource/icons/info.png"))); layerSelectable.setToolTipText(GeopublisherGUI .R("LayerToolMenu.selectable.TT")); layerSelectable.setSelected(map.isSelectableFor(styledLayer.getId())); boolean hasVisibleAttributesOrIsGrid = hasVisibleAttributesOrIsGrid(); layerSelectable.setEnabled(hasVisibleAttributesOrIsGrid); if (!hasVisibleAttributesOrIsGrid) { layerSelectable.setText(GeopublisherGUI .R("LayerToolMenu.NOT.selectable")); } menu.add(layerSelectable); return menu; } @Override public DesignAtlasStylerDialog openStylerDialog() { LayerStyle selectedStyle = map.getSelectedStyle(dpLayer.getId()); Object key = selectedStyle == null ? dpLayer : selectedStyle; return GPDialogManager.dm_DesignAtlasStyler.getInstanceFor(key, mapLegend, dpLayer, mapLegend, getMapLayer(), selectedStyle); } /** * Change the visibility of the associated {@link MapLayer} (on/off). This * overwritten method also stores the information in the {@link Map} */ @Override public boolean toggleVisibility() { boolean result = super.toggleVisibility(); map.setHiddenFor(dpLayer.getId(), !result); Boolean hiddenFor = map.getHiddenFor(dpLayer.getId()); LOGGER.debug(dpLayer.getId() + " hidden flag is set to " + hiddenFor); return result; } }