/* * Copyright 2013 Serdar. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.fub.maps.project.aggregator.filetype; import de.fub.agg2graph.structs.DoubleRect; import de.fub.agg2graphui.controller.AbstractLayer; import de.fub.maps.project.aggregator.factories.LayerNodeFactory; import de.fub.maps.project.aggregator.pipeline.AbstractAggregationProcess; import de.fub.maps.project.aggregator.xml.Source; import de.fub.maps.project.models.Aggregator; import de.fub.maps.project.ui.component.StatisticsPanel; import de.fub.maps.project.utils.LayerTableCellRender; import de.fub.mapviewer.ui.MapViewerTileFactory; import de.fub.utilsmodule.icons.IconRegister; import geofiletypeapi.GeoUtil; import java.awt.Dimension; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.geom.Area; import java.awt.geom.Rectangle2D; import java.beans.BeanInfo; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import javax.swing.Action; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JToggleButton; import javax.swing.JToolBar; import javax.swing.MenuElement; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.jdesktop.swingx.mapviewer.TileFactory; import org.netbeans.api.annotations.common.StaticResource; import org.netbeans.core.spi.multiview.CloseOperationState; import org.netbeans.core.spi.multiview.MultiViewElement; import org.netbeans.core.spi.multiview.MultiViewElementCallback; import org.openide.DialogDescriptor; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.awt.DropDownButtonFactory; import org.openide.awt.UndoRedo; import org.openide.explorer.ExplorerManager; import org.openide.explorer.ExplorerUtils; import org.openide.loaders.DataObject; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.util.ImageUtilities; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.RequestProcessor; import org.openide.util.WeakListeners; import org.openide.util.lookup.Lookups; import org.openide.util.lookup.ProxyLookup; import org.openide.windows.TopComponent; /** * * @author Serdar */ @MultiViewElement.Registration( displayName = "#LBL_AggregationBuilder_VISUAL", iconBase = "de/fub/maps/project/aggregator/filetype/aggregationBuilderIcon.png", mimeType = {"text/aggregationbuilder+xml", "application/map"}, persistenceType = TopComponent.PERSISTENCE_NEVER, preferredID = "AggregationVisualElement", position = 1000) @NbBundle.Messages("LBL_AggregationBuilder_VISUAL=Map") public class AggregationVisualElement extends javax.swing.JPanel implements MultiViewElement, PropertyChangeListener, ExplorerManager.Provider { private static final long serialVersionUID = 1L; @StaticResource private static final String LAYER_ICON_PATH = "de/fub/maps/project/aggregator/filetype/layersIcon.png"; @StaticResource private static final String LAYERVIEW_ICON_PATH = "de/fub/maps/project/aggregator/filetype/layerview.png"; @StaticResource private static final String STATISTICS_BUTTON_ICON_PATH = "de/fub/maps/project/aggregator/statisticsIcon.png"; @StaticResource private static final String FIT_MAP_TO_SIZE_BUTTON_ICON_PATH = "de/fub/maps/project/aggregator/filetype/zoomToMap.png"; @StaticResource private static final String STATUS_BAR_VISIBLE_ICON_PATH = "de/fub/maps/project/aggregator/filetype/statusbarIcon.png"; private final JToolBar toolbar = new JToolBar(); private final ExplorerManager explorerManager = new ExplorerManager(); private transient final RequestProcessor requestProcessor = new RequestProcessor(); // private transient final ModelSynchronizer.ModelSynchronizerClient modelSynchronizerClient; private transient final ViewUpdater viewUpdater = new ViewUpdater(); private transient final LayerNodeFactory nodeFactory = new LayerNodeFactory(); private transient final Lookup lookup; private transient MultiViewElementCallback callback; private transient Aggregator aggregator; // private transient Image defaulImage; private JToggleButton layerViewButton; private JButton layersButton; private JButton processRunButton; private JButton statisticsDataButton; private JButton fitToSizeButton; private JPopupMenu layersMenu; private JPopupMenu processMenu; private JComboBox<MapViewerTileFactory> tileSourceComboBox; private JToggleButton statusBarButton; private transient final Object MUTEX_UPDATE = new Object(); /** * Creates new form AggregationVisualElement * * @param lkp */ public AggregationVisualElement(Lookup lkp) { DataObject dataObject = lkp.lookup(DataObject.class); if (dataObject != null) { aggregator = dataObject.getNodeDelegate().getLookup().lookup(Aggregator.class); } assert aggregator != null; lookup = new ProxyLookup(Lookups.singleton(AggregationVisualElement.this), ExplorerUtils.createLookup(explorerManager, getActionMap())); explorerManager.setRootContext(new AbstractNode(Children.create(nodeFactory, true))); aggregator.addPropertyChangeListener(WeakListeners.propertyChange(AggregationVisualElement.this, aggregator)); aggregator.create(viewUpdater); initGuiComponents(); } private void initGuiComponents() { initComponents(); toolbar.setFloatable(false); toolbar.add(new JToolBar.Separator()); setUpToolbar(); outlineView1.getOutline().setRowHeight(300); outlineView1.getOutline().setRootVisible(false); outlineView1.getOutline().setDefaultRenderer(Object.class, new LayerTableCellRender()); jSplitPane1.setDividerLocation(Integer.MAX_VALUE); } /** * initializes and sets up the drop down menu of the Layer visiblity menu. */ private void initPopupMenu() { nodeFactory.clear(); aggComponent.clear(); Collection<AbstractAggregationProcess<?, ?>> processes = aggregator.getPipeline().getProcesses(); for (AbstractAggregationProcess<?, ?> process : processes) { for (final AbstractLayer<?> layer : process.getLayers()) { aggComponent.addLayer(layer); nodeFactory.add(layer); final JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem(layer.getName()); jCheckBoxMenuItem.setState(layer.isVisible()); jCheckBoxMenuItem.addActionListener(new LayerActionListener(layer, jCheckBoxMenuItem)); layersMenu.add(jCheckBoxMenuItem); } } } /** * initializes and sets up the drop down menu of the process run toolbar * button. */ private void initProcessPopupMenu() { Collection<AbstractAggregationProcess<?, ?>> processes = aggregator.getPipeline().getProcesses(); for (final AbstractAggregationProcess<?, ?> process : processes) { final JMenuItem menuItem = new JMenuItem(process.getName()); menuItem.setToolTipText(process.getDescription()); menuItem.addActionListener(new ActionListener() { @Override @SuppressWarnings("unchecked") public void actionPerformed(ActionEvent e) { requestProcessor.post(new Runnable() { @Override public void run() { aggregator.start((List<AbstractAggregationProcess<?, ?>>) Arrays.asList(process)); } }); } }); processMenu.add(menuItem); } } @NbBundle.Messages({"CLT_Information_Message=Task still running!", "CLT_Process_Button_Tooltip=Run pipline", "CLT_Show_Hide_Layers=Shows/Hides Layers", "CLT_Show_Hide_Layer_View=Shows/Hides Layer View", "CLT_Statistics_Button_Tooltip=Displays all available Statistics of this Aggregator.", "CLT_Statistics_Window=Statistics", "CLT_Fit_Map_To_Size_Tooltip=Zoom the map to the size of the viewport.", "CLT_StatusBar_Button_Tooltip=Status bar enable/disable" }) private void setUpToolbar() { // set up tilesource combobox if (tileSourceComboBox == null) { Collection<? extends MapViewerTileFactory> tileSources = Lookup.getDefault().lookupResult(MapViewerTileFactory.class).allInstances(); tileSourceComboBox = new JComboBox<MapViewerTileFactory>(tileSources.toArray(new MapViewerTileFactory[tileSources.size()])); tileSourceComboBox.setMaximumSize(new Dimension(150, 16)); tileSourceComboBox.setSelectedIndex(0); TileFactory tileFactory = aggComponent.getTileFactory(); if (!tileSources.isEmpty()) { if (tileFactory != null) { for (TileFactory tilef : tileSources) { if (tileFactory.getInfo().getName().equals(tilef.getInfo().getName())) { tileSourceComboBox.setSelectedItem(tilef); break; } } } else { aggComponent.setTileFactory(tileSources.iterator().next()); } } tileSourceComboBox.addItemListener(new TileSourceComboBoxItemListenerImpl()); toolbar.add(tileSourceComboBox); toolbar.add(new JToolBar.Separator()); } // set up statistics button if (statisticsDataButton == null) { statisticsDataButton = new JButton(ImageUtilities.loadImageIcon(STATISTICS_BUTTON_ICON_PATH, true)); statisticsDataButton.setToolTipText(Bundle.CLT_Statistics_Button_Tooltip()); statisticsDataButton.addActionListener(new StatisticsDataButtonActionListenerImpl()); toolbar.add(statisticsDataButton); toolbar.add(new JToolBar.Separator()); } // set up layer show/hide drop down button if (layersMenu == null) { layersMenu = new JPopupMenu(); initPopupMenu(); layersButton = DropDownButtonFactory.createDropDownButton(ImageUtilities.loadImageIcon(LAYER_ICON_PATH, true), layersMenu); layersButton.setToolTipText(Bundle.CLT_Show_Hide_Layers()); layersButton.addActionListener(new LayerButtonActionListenerImpl()); toolbar.add(layersButton); } else { layersMenu.removeAll(); initPopupMenu(); } // set up layer view button if (layerViewButton == null) { layerViewButton = new JToggleButton(ImageUtilities.loadImageIcon(LAYERVIEW_ICON_PATH, true)); layerViewButton.setSelected(false); layerViewButton.setToolTipText(Bundle.CLT_Show_Hide_Layer_View()); layerViewButton.addActionListener(new LayerViewButtonActionListenerImpl()); toolbar.add(layerViewButton); } // set up fit map to size button if (fitToSizeButton == null) { fitToSizeButton = new JButton(ImageUtilities.loadImageIcon(FIT_MAP_TO_SIZE_BUTTON_ICON_PATH, true)); fitToSizeButton.setToolTipText(Bundle.CLT_Fit_Map_To_Size_Tooltip()); fitToSizeButton.addActionListener(new FitToSizeButtonActionListenerImpl()); toolbar.add(fitToSizeButton); toolbar.add(new JToolBar.Separator()); } // set up process drop down button if (processMenu == null) { processMenu = new JPopupMenu(); initProcessPopupMenu(); Image buttonImageIcon = IconRegister.findRegisteredIcon("toolbarProcessRunIcon.png"); processRunButton = DropDownButtonFactory.createDropDownButton(new ImageIcon(buttonImageIcon), processMenu); processRunButton.setToolTipText(Bundle.CLT_Process_Button_Tooltip()); processRunButton.addActionListener(new ProcessRunButtonActionListenerImpl()); toolbar.add(processRunButton); } else { processMenu.removeAll(); initProcessPopupMenu(); } if (this.statusBarButton == null) { statusBarButton = new JToggleButton(ImageUtilities.loadImageIcon(STATUS_BAR_VISIBLE_ICON_PATH, true)); statusBarButton.setToolTipText(Bundle.CLT_StatusBar_Button_Tooltip()); statusBarButton.addActionListener(new StatusBarButtonActionListenerImpl()); // default setting: status bar is visible statusBarButton.doClick(); toolbar.addSeparator(); toolbar.add(statusBarButton); toolbar.addSeparator(); } } private void updateLayerView() { if (layerViewButton.isSelected()) { jSplitPane1.setEnabled(true); jSplitPane1.setDividerLocation(.8); } else { jSplitPane1.setEnabled(false); jSplitPane1.setDividerLocation(1d); } } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { jSplitPane1 = new javax.swing.JSplitPane(); outlineView1 = new org.openide.explorer.view.OutlineView("Layers"); aggComponent = new de.fub.agg2graphui.AggTopComponent(); setLayout(new java.awt.BorderLayout()); jSplitPane1.setDividerLocation(1000000); jSplitPane1.setResizeWeight(1.0); jSplitPane1.setEnabled(false); jSplitPane1.setMinimumSize(new java.awt.Dimension(400, 276)); outlineView1.setMinimumSize(new java.awt.Dimension(0, 25)); outlineView1.setPreferredSize(new java.awt.Dimension(0, 400)); jSplitPane1.setRightComponent(outlineView1); aggComponent.setMinimumSize(new java.awt.Dimension(400, 274)); jSplitPane1.setLeftComponent(aggComponent); add(jSplitPane1, java.awt.BorderLayout.CENTER); }// </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private de.fub.agg2graphui.AggTopComponent aggComponent; private javax.swing.JSplitPane jSplitPane1; private org.openide.explorer.view.OutlineView outlineView1; // End of variables declaration//GEN-END:variables @Override public JComponent getVisualRepresentation() { return this; } @Override public JComponent getToolbarRepresentation() { return toolbar; } @Override public Action[] getActions() { Action[] retValue; // the multiviewObserver was passed to the element in setMultiViewCallback() method. if (callback != null) { retValue = callback.createDefaultActions(); // add you own custom actions here.. } else { // fallback.. retValue = new Action[0]; } return retValue; } @Override public Lookup getLookup() { return lookup; } @Override public void componentOpened() { requestProcessor.post(new Runnable() { @Override public void run() { updateMap(); } }); } @Override public void componentClosed() { } @Override public void componentShowing() { } @Override public void componentHidden() { } @Override public void componentActivated() { } @Override public void componentDeactivated() { } @Override public UndoRedo getUndoRedo() { return UndoRedo.NONE; } @Override public void setMultiViewCallback(MultiViewElementCallback callback) { this.callback = callback; if (this.callback != null && aggregator != null) { this.callback.getTopComponent().setDisplayName(aggregator.getAggregatorDescriptor().getName()); } } @Override public CloseOperationState canCloseElement() { return aggregator.getAggregatorState() != Aggregator.AggregatorState.RUNNING ? CloseOperationState.STATE_OK : null; } @Override public void propertyChange(PropertyChangeEvent evt) { if (Aggregator.PROP_NAME_AGGREGATOR_STATE.equals(evt.getPropertyName()) && callback != null) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { TopComponent topComponent = callback.getTopComponent(); if (callback.isSelectedElement()) { topComponent.setIcon(aggregator.getDataObject().getNodeDelegate().getIcon(BeanInfo.ICON_COLOR_16x16)); } } }); } } @Override public ExplorerManager getExplorerManager() { return explorerManager; } private void updateMap() { if (fitToSizeButton.isEnabled()) { synchronized (MUTEX_UPDATE) { fitToSizeButton.setEnabled(false); try { List<Source> sourceList = aggregator.getSourceList(); if (sourceList != null) { Area totalBoundingBox = new Area(); for (Source source : sourceList) { String url = source.getUrl(); if (url != null) { File file = new File(url); Rectangle2D boundingBox = GeoUtil.getBoundingBox(file); if (boundingBox != null) { totalBoundingBox.add(new Area(boundingBox)); } } } Rectangle2D bounds = totalBoundingBox.getBounds2D(); aggComponent.showArea( new DoubleRect( bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight())); } } finally { fitToSizeButton.setEnabled(true); } } } } private class ViewUpdater implements ChangeListener { @Override public void stateChanged(ChangeEvent e) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { setUpToolbar(); } }); } } private static class LayerActionListener implements ActionListener { private final AbstractLayer<?> layer; private final JCheckBoxMenuItem jCheckBoxMenuItem; public LayerActionListener(AbstractLayer<?> layer, JCheckBoxMenuItem jCheckBoxMenuItem) { this.layer = layer; this.jCheckBoxMenuItem = jCheckBoxMenuItem; } @Override public void actionPerformed(ActionEvent e) { layer.setVisible(jCheckBoxMenuItem.getState()); } } private class TileSourceComboBoxItemListenerImpl implements ItemListener { public TileSourceComboBoxItemListenerImpl() { } @Override public void itemStateChanged(ItemEvent e) { if (tileSourceComboBox.getSelectedItem() instanceof TileFactory) { aggComponent.setTileFactory((TileFactory) tileSourceComboBox.getSelectedItem()); } } } private class StatisticsDataButtonActionListenerImpl implements ActionListener { public StatisticsDataButtonActionListenerImpl() { } @Override public void actionPerformed(ActionEvent e) { if (aggregator != null) { StatisticsPanel statisticsPanel = new StatisticsPanel(aggregator.getStatistics()); DialogDescriptor dd = new DialogDescriptor(statisticsPanel, Bundle.CLT_Statistics_Window()); dd.setOptionType(DialogDescriptor.DEFAULT_OPTION); DialogDisplayer.getDefault().notifyLater(dd); } } } private class LayerButtonActionListenerImpl implements ActionListener { public LayerButtonActionListenerImpl() { } private boolean allVisible = true; @Override public void actionPerformed(ActionEvent e) { allVisible = !allVisible; MenuElement[] subElements = layersMenu.getSubElements(); for (MenuElement element : subElements) { if (element instanceof JCheckBoxMenuItem) { JCheckBoxMenuItem item = (JCheckBoxMenuItem) element; item.doClick(); } } } } private class LayerViewButtonActionListenerImpl implements ActionListener { public LayerViewButtonActionListenerImpl() { } @Override public void actionPerformed(ActionEvent e) { updateLayerView(); } } private class FitToSizeButtonActionListenerImpl implements ActionListener { public FitToSizeButtonActionListenerImpl() { } @Override public void actionPerformed(ActionEvent e) { requestProcessor.post(new Runnable() { @Override public void run() { updateMap(); } }); } } private class ProcessRunButtonActionListenerImpl implements ActionListener { public ProcessRunButtonActionListenerImpl() { if (aggregator != null) { aggregator.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (Aggregator.AggregatorState.RUNNING == aggregator.getAggregatorState()) { processRunButton.setEnabled(false); } else { processRunButton.setEnabled(true); } } }); } } @Override public void actionPerformed(ActionEvent e) { if (aggregator.getAggregatorState() != Aggregator.AggregatorState.RUNNING) { requestProcessor.post(new Runnable() { @Override public void run() { aggregator.start(new ArrayList<AbstractAggregationProcess<?, ?>>(aggregator.getPipeline().getProcesses())); } }); } else { NotifyDescriptor nd = new NotifyDescriptor.Message(Bundle.CLT_Information_Message(), NotifyDescriptor.ERROR_MESSAGE); DialogDisplayer.getDefault().notifyLater(nd); } } } private class StatusBarButtonActionListenerImpl implements ActionListener { public StatusBarButtonActionListenerImpl() { } @Override public void actionPerformed(ActionEvent e) { aggComponent.setStatusBarVisible(statusBarButton.isSelected()); } } }