Java tutorial
/* This file is part of RouteConverter. RouteConverter is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. RouteConverter 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 GNU General Public License for more details. You should have received a copy of the GNU General Public License along with RouteConverter; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Copyright (C) 2007 Christian Pesch. All Rights Reserved. */ package slash.navigation.converter.gui.profileview; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartMouseEvent; import org.jfree.chart.ChartMouseListener; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.entity.ChartEntity; import org.jfree.chart.entity.XYItemEntity; import org.jfree.chart.labels.StandardXYToolTipGenerator; import org.jfree.chart.plot.ValueMarker; import org.jfree.chart.plot.XYPlot; import org.jfree.data.xy.XYDataset; import org.jfree.data.xy.XYSeriesCollection; import slash.navigation.common.UnitSystem; import slash.navigation.converter.gui.models.*; import slash.navigation.gui.Application; import slash.navigation.gui.actions.ActionManager; import slash.navigation.gui.actions.FrameAction; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.*; import java.util.ResourceBundle; import java.util.prefs.Preferences; import static java.text.MessageFormat.format; import static java.text.NumberFormat.getIntegerInstance; import static org.jfree.chart.axis.NumberAxis.createIntegerTickUnits; import static org.jfree.chart.plot.PlotOrientation.VERTICAL; import static org.jfree.ui.Layer.FOREGROUND; import static slash.navigation.converter.gui.profileview.ProfileMode.Elevation; /** * Displays the elevations of a {@link PositionsModel}. * * @author Christian Pesch */ public class ProfileView implements PositionsSelectionModel { protected static final Preferences preferences = Preferences.userNodeForPackage(ProfileView.class); private static final String X_GRID_PREFERENCE = "xGrid"; private static final String Y_GRID_PREFERENCE = "yGrid"; private LazyToolTipChartPanel chartPanel; private XYPlot plot; private PositionsModel positionsModel; private ProfileModel profileModel; public void initialize(PositionsModel positionsModel, final PositionsSelectionModel positionsSelectionModel, final UnitSystemModel unitSystemModel, final ProfileModeModel profileModeModel) { this.positionsModel = positionsModel; PatchedXYSeries series = new PatchedXYSeries("Profile"); this.profileModel = new ProfileModel(positionsModel, series, unitSystemModel.getUnitSystem(), profileModeModel.getProfileMode()); XYSeriesCollection dataset = new XYSeriesCollection(series); unitSystemModel.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { setUnitSystem(unitSystemModel.getUnitSystem()); } }); profileModeModel.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { setProfileMode(profileModeModel.getProfileMode()); } }); JFreeChart chart = createChart(dataset); plot = createPlot(chart); ActionManager actionManager = Application.getInstance().getContext().getActionManager(); for (ProfileMode mode : ProfileMode.values()) actionManager.register("show-" + mode.name().toLowerCase(), new ToggleProfileModeAction(profileModeModel, mode)); // since JFreeChart is not very nice to extensions - constructors calling protected methods... ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD LazyToolTipChartPanel.profileModeModel = profileModeModel; chartPanel = new LazyToolTipChartPanel(chart, false, true, true, true, true); chartPanel.addChartMouseListener(new ChartMouseListener() { public void chartMouseClicked(ChartMouseEvent e) { ChartEntity entity = e.getEntity(); if (!(entity instanceof XYItemEntity)) return; int row = ((XYItemEntity) entity).getItem(); positionsSelectionModel.setSelectedPositions(new int[] { row }, true); } public void chartMouseMoved(ChartMouseEvent e) { } }); chartPanel.setMouseWheelEnabled(true); updateAxis(); } private static ResourceBundle getBundle() { return Application.getInstance().getContext().getBundle(); } private JFreeChart createChart(XYDataset dataset) { JFreeChart chart = ChartFactory.createXYAreaChart(null, null, null, dataset, VERTICAL, false, true, false); chart.setBackgroundPaint(new JPanel().getBackground()); return chart; } private XYPlot createPlot(JFreeChart chart) { XYPlot plot = chart.getXYPlot(); plot.setForegroundAlpha(0.65F); plot.setDomainGridlinesVisible(preferences.getBoolean(X_GRID_PREFERENCE, true)); plot.setRangeGridlinesVisible(preferences.getBoolean(Y_GRID_PREFERENCE, true)); NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis(); rangeAxis.setStandardTickUnits(createIntegerTickUnits()); Font font = new JLabel().getFont(); rangeAxis.setLabelFont(font); NumberAxis valueAxis = (NumberAxis) plot.getDomainAxis(); valueAxis.setStandardTickUnits(createIntegerTickUnits()); valueAxis.setLowerMargin(0.0); valueAxis.setUpperMargin(0.0); valueAxis.setLabelFont(font); plot.getRenderer().setBaseToolTipGenerator(null); return plot; } public Component getComponent() { return chartPanel; } private void setUnitSystem(UnitSystem unitSystem) { profileModel.setUnitSystem(unitSystem); updateAxis(); } private void setProfileMode(ProfileMode profileMode) { profileModel.setProfileMode(profileMode); updateAxis(); } private void updateAxis() { UnitSystem unitSystem = profileModel.getUnitSystem(); ProfileMode profileMode = profileModel.getProfileMode(); plot.getDomainAxis().setLabel(format(getBundle().getString("distance-axis"), unitSystem.getDistanceName())); String yAxisUnit = profileMode.equals(Elevation) ? unitSystem.getElevationName() : unitSystem.getSpeedName(); String yAxisKey = profileMode.equals(Elevation) ? "elevation-axis" : "speed-axis"; plot.getRangeAxis().setLabel(format(getBundle().getString(yAxisKey), yAxisUnit)); chartPanel.setToolTipGenerator( new StandardXYToolTipGenerator("{2} " + yAxisUnit + " @ {1} " + unitSystem.getDistanceName(), getIntegerInstance(), getIntegerInstance()) { public String generateLabelString(XYDataset dataset, int series, int item) { return super.generateLabelString(dataset, series, item).replaceAll("null", "?"); } }); } public void setSelectedPositions(int[] selectPositions, boolean replaceSelection) { if (replaceSelection) plot.clearDomainMarkers(); double[] distances = positionsModel.getRoute().getDistancesFromStart(selectPositions); for (double distance : distances) { plot.addDomainMarker(0, new ValueMarker(profileModel.formatDistance(distance)), FOREGROUND, false); } // make sure the protected fireChangeEvent() is called without any side effects plot.setWeight(plot.getWeight()); } public void print() { chartPanel.createChartPrintJob(); } private static class ToggleProfileModeAction extends FrameAction { private final ProfileModeModel profileModeModel; private final ProfileMode profileMode; public ToggleProfileModeAction(ProfileModeModel profileModeModel, ProfileMode profileMode) { this.profileModeModel = profileModeModel; this.profileMode = profileMode; } public void run() { profileModeModel.setProfileMode(profileMode); } } }