/* * Copyright (C) 2011 Andrea Schweer * * This file is part of the Digital Parrot. * * The Digital Parrot is free software; you can redistribute it and/or modify * it under the terms of the Eclipse Public License as published by the Eclipse * Foundation or its Agreement Steward, either version 1.0 of the License, or * (at your option) any later version. * * The Digital Parrot is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the Eclipse Public License for * more details. * * You should have received a copy of the Eclipse Public License along with the * Digital Parrot. If not, see http://www.eclipse.org/legal/epl-v10.html. * */ package net.schweerelos.parrot.ui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Window; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Properties; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.DefaultListCellRenderer; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JScrollPane; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import net.schweerelos.parrot.model.CenteredThing; import net.schweerelos.parrot.model.CoordinatePrecision; import net.schweerelos.parrot.model.Filter; import net.schweerelos.parrot.model.LocatedThingsHelper; import net.schweerelos.parrot.model.NodeWrapper; import net.schweerelos.parrot.model.NotPlacedThingException; import net.schweerelos.parrot.model.ParrotModel; import net.schweerelos.parrot.model.Filter.Mode; import net.schweerelos.parrot.model.filters.MapAreaFilter; import net.schweerelos.parrot.model.filters.SimpleNodeFilter; import net.schweerelos.parrot.util.LatLonBounds; @SuppressWarnings("serial") public class WebRendererMapNavigator extends AbstractNavigatorPanel { private final class ShowInMapAction extends AbstractAction { private final NodeWrapper node; private ShowInMapAction(NodeWrapper node) { super("Show in map"); this.node = node; } @Override public void actionPerformed(ActionEvent e) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { try { mapBrowser.focusMapOn(LocatedThingsHelper .getAsLocatedThing(node)); Window window = SwingUtilities.getWindowAncestor( WebRendererMapNavigator.this); if (window != null) { window.setVisible(true); } } catch (NotPlacedThingException e) { /* ignore */ } } }); } } private static final String NAME = "Map"; private static final String ACCELERATOR_KEY = "M"; private static final Color COLOR_EVEN_ROW_UNSELECTED_BG = Color.WHITE; private static final Color COLOR_ODD_ROW_UNSELECTED_BG = UIConstants.ENVIRONMENT_LIGHTEST; private static final Color COLOR_SELECTED_BG = UIConstants.THIRD_ACCENT_LIGHT; private static final Color COLOR_SELECTED_BORDER = UIConstants.THIRD_ACCENT_MEDIUM; private Filter lastRestrictingFilter; private Filter lastHighlightFilter; private JList placesList; private MapBrowser mapBrowser; public WebRendererMapNavigator(Properties properties) { super(); setLayout(new BorderLayout()); placesList = new JList(); FontMetrics metrics = placesList.getFontMetrics(placesList.getFont()); int rowHeight = 2 * metrics.getMaxAscent() + 2 * metrics.getMaxDescent() + metrics.getLeading(); placesList.setFixedCellHeight(rowHeight); placesList.setCellRenderer(new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { Component renderer = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (renderer instanceof JLabel && value instanceof CenteredThing<?>) { JLabel label = (JLabel) renderer; CenteredThing<?> thing = (CenteredThing<?>) value; label.setText(thing.getLabel()); label.setFont(label.getFont().deriveFont(Font.PLAIN)); if (isSelected || cellHasFocus) { label.setBackground(COLOR_SELECTED_BG); label.setBorder(BorderFactory.createLineBorder( COLOR_SELECTED_BORDER, 2)); } else { if (index % 2 == 0) { label.setBackground(COLOR_EVEN_ROW_UNSELECTED_BG); } else { label.setBackground(COLOR_ODD_ROW_UNSELECTED_BG); } } } return renderer; } }); placesList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); placesList.addListSelectionListener(new ListSelectionListener() { @SuppressWarnings("unchecked") @Override public void valueChanged(ListSelectionEvent lse) { if (lse.getValueIsAdjusting()) { return; } Object selectedValue = placesList.getSelectedValue(); try { final CenteredThing<NodeWrapper> selected = (CenteredThing<NodeWrapper>) selectedValue; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { mapBrowser.focusMapOn(selected); } }); } catch (ClassCastException cce) { /* ignore */ } } }); add(new JScrollPane(placesList), BorderLayout.LINE_START); mapBrowser = new MapBrowser(properties.getProperty("webrenderer.license.type"), properties.getProperty("webrenderer.license.data")); mapBrowser.addMapBrowserListener(new MapBrowserListener() { @Override public void panned(final LatLonBounds newBounds) { SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { @Override protected Void doInBackground() throws Exception { Window parent = SwingUtilities .getWindowAncestor(WebRendererMapNavigator.this); parent.setCursor(Cursor .getPredefinedCursor(Cursor.WAIT_CURSOR)); adjustRestrictingFilter(newBounds); return null; } @Override protected void done() { Window parent = SwingUtilities .getWindowAncestor(WebRendererMapNavigator.this); parent.setCursor(Cursor.getDefaultCursor()); } }; worker.execute(); } @Override public void markerClicked(NodeWrapper marker) { adjustHighlightingFilter(marker); } @Override public void zoomed(int zoom) { // ignore for now } }); add(mapBrowser, BorderLayout.CENTER); } protected void adjustHighlightingFilter(final NodeWrapper marker) { if (getModel() == null) { return; } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { Filter oldHighlightFilter = lastHighlightFilter; lastHighlightFilter = new SimpleNodeFilter() { @Override protected boolean matches(NodeWrapper nodeWrapper) { return nodeWrapper.equals(marker); } }; lastHighlightFilter.setMode(Mode.HIGHLIGHT); replaceFilter(oldHighlightFilter, lastHighlightFilter); } }); } private void adjustRestrictingFilter(final LatLonBounds newBounds) { if (getModel() == null) { return; } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { Filter oldRestrictingFilter = lastRestrictingFilter; lastRestrictingFilter = new MapAreaFilter(newBounds); lastRestrictingFilter.setMode(Mode.RESTRICT); replaceFilter(oldRestrictingFilter, lastRestrictingFilter); } }); } @Override public void setModel(ParrotModel model) { List<CenteredThing<NodeWrapper>> locatedThings = model .getLocatedThings().getAll(); initPlacesList(locatedThings); mapBrowser.setModel(model); super.setModel(model); } private void initPlacesList(List<CenteredThing<NodeWrapper>> locatedThings) { List<CenteredThing<NodeWrapper>> bigEnoughLocatedThings = new ArrayList<CenteredThing<NodeWrapper>>(); for (CenteredThing<NodeWrapper> thing : locatedThings) { if (thing.getPrecision().compareTo( CoordinatePrecision.BlockPrecision) >= 0) { bigEnoughLocatedThings.add(thing); } } Collections.sort(bigEnoughLocatedThings, new Comparator<CenteredThing<NodeWrapper>>() { @Override public int compare(CenteredThing<NodeWrapper> o1, CenteredThing<NodeWrapper> o2) { return o1.getLabel().compareTo(o2.getLabel()); } }); placesList.setListData(bigEnoughLocatedThings.toArray()); } @Override protected void activateFilters() { if (getModel() == null) { return; } if (lastRestrictingFilter != null) { applyFilter(lastRestrictingFilter); } if (lastHighlightFilter != null) { applyFilter(lastHighlightFilter); } } @Override protected void deactivateFilters() { if (getModel() == null) { return; } if (lastRestrictingFilter != null) { removeFilter(lastRestrictingFilter); } if (lastHighlightFilter != null) { applyFilter(lastHighlightFilter); } } @Override public List<Action> getActionsForNode(final NodeWrapper currentNode) { ArrayList<Action> result = new ArrayList<Action>(); if (LocatedThingsHelper.isLocatedThing(currentNode, getModel())) { Action showInMap = new ShowInMapAction(currentNode); result.add(showInMap); } return result; } @Override public List<Action> getActionsForType(NodeWrapper type) { // map doesn't deal with types return Collections.emptyList(); } @Override public String getNavigatorName() { return NAME; } @Override public String getAcceleratorKey() { return ACCELERATOR_KEY; } }