diff --git a/src/main/java/com/tagtraum/perf/gcviewer/ChartPanelView.java b/src/main/java/com/tagtraum/perf/gcviewer/ChartPanelView.java index 1b207231..c2d01148 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/ChartPanelView.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/ChartPanelView.java @@ -58,10 +58,12 @@ public class ChartPanelView { private TextAreaLogHandler textAreaLogHandler; private DataReaderFacade dataReaderFacade; - public ChartPanelView(GCDocument gcDocument, URL url) throws DataReaderException { + private GCViewerGui gui; + + public ChartPanelView(GCViewerGui gui, GCDocument gcDocument, URL url) throws DataReaderException { this.gcDocument = gcDocument; this.preferences = gcDocument.getPreferences(); - this.modelChart = new ModelChartImpl(); + this.modelChart = new ModelChartImpl(gui); this.modelPanel = new ModelPanel(); this.modelDetailsPanel = new ModelDetailsPanel(); diff --git a/src/main/java/com/tagtraum/perf/gcviewer/GCDocument.java b/src/main/java/com/tagtraum/perf/gcviewer/GCDocument.java index 573d2f71..0a3ca23a 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/GCDocument.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/GCDocument.java @@ -49,11 +49,13 @@ public class GCDocument extends JInternalFrame { private boolean watched; private RefreshWatchDog refreshWatchDog; private GCPreferences preferences; + private GCViewerGui gui; public GCDocument(final GCViewerGui gcViewer, String s) { super(s, true, true, true, false); this.refreshWatchDog = new RefreshWatchDog(); refreshWatchDog.setGcDocument(this); + this.gui = gcViewer; preferences = gcViewer.getPreferences(); showModelPanel = preferences.isShowDataPanel(); modelChartListFacade = new MultiModelChartFacade(); @@ -144,7 +146,7 @@ public GCPreferences getPreferences() { } public void add(final URL url) throws DataReaderException { - ChartPanelView chartPanelView = new ChartPanelView(this, url); + ChartPanelView chartPanelView = new ChartPanelView(gui, this, url); chartPanelViews.add(chartPanelView); chartPanelView.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { diff --git a/src/main/java/com/tagtraum/perf/gcviewer/GCViewerGui.java b/src/main/java/com/tagtraum/perf/gcviewer/GCViewerGui.java index 29ea6155..d8d0c2f5 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/GCViewerGui.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/GCViewerGui.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.text.DecimalFormat; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -29,6 +30,7 @@ import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.ButtonGroup; +import javax.swing.DefaultComboBoxModel; import javax.swing.ImageIcon; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; @@ -85,7 +87,7 @@ public class GCViewerGui extends JFrame { private static final Logger LOGGER = Logger.getLogger(GCViewerGui.class.getName()); - + private static final DecimalFormat ZOOM_FORMAT = new DecimalFormat("#"); private JToolBar toolBar; private ActionListener viewMenuActionListener; private JMenu fileMenu; @@ -126,7 +128,7 @@ public class GCViewerGui extends JFrame { private JCheckBoxMenuItem menuItemAntiAlias; private Map gcLineMenuItems; private JToggleButton watchToggle; - + private DefaultComboBoxModel zoomValues = new DefaultComboBoxModel<>(new String[] {"1%", "5%", "10%", "50%", "100%", "200%", "300%", "500%", "1000%", "5000%"}); private RecentURLsMenu recentURLsMenu; private GCPreferences preferences; @@ -397,11 +399,12 @@ private JToolBar initToolBar() { watchToggle.setText(""); toolBar.add(watchToggle); toolBar.addSeparator(); - zoomComboBox = new JComboBox(new String[] {"1%", "5%", "10%", "50%", "100%", "200%", "300%", "500%", "1000%", "5000%"}); + zoomComboBox = new JComboBox<>(zoomValues); zoomComboBox.setSelectedIndex(2); zoomComboBox.setAction(zoomAction); zoomComboBox.setEditable(true); zoomComboBox.setMaximumSize(zoomComboBox.getPreferredSize()); + zoomComboBox.setName("zoomComboBox"); toolBar.add(zoomComboBox); toolBar.addSeparator(); toolBar.add(aboutAction); @@ -791,6 +794,12 @@ private void storePreferences(GCPreferences preferences) { preferences.store(); } + public void setZoomValue(final double zoom) { + if(!"1%".equals(zoomValues.getElementAt(0))) + this.zoomValues.removeElementAt(0); + this.zoomValues.insertElementAt(ZOOM_FORMAT.format((zoom * 1000)).concat("%"), 0); + this.zoomComboBox.setSelectedIndex(0); + } public static void start(final String arg) { SwingUtilities.invokeLater(new Runnable() { public void run() { diff --git a/src/main/java/com/tagtraum/perf/gcviewer/ModelChartImpl.java b/src/main/java/com/tagtraum/perf/gcviewer/ModelChartImpl.java index 83bb9b9a..ae730647 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/ModelChartImpl.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/ModelChartImpl.java @@ -1,19 +1,51 @@ package com.tagtraum.perf.gcviewer; -import com.tagtraum.perf.gcviewer.model.GCModel; -import com.tagtraum.perf.gcviewer.renderer.*; -import com.tagtraum.perf.gcviewer.util.TimeFormat; - -import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.*; -import java.awt.event.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.text.DateFormat; import java.text.Format; import java.text.NumberFormat; import java.util.Date; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.JViewport; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import com.tagtraum.perf.gcviewer.action.ZoomMouseListener; +import com.tagtraum.perf.gcviewer.model.GCModel; +import com.tagtraum.perf.gcviewer.renderer.ConcurrentGcBegionEndRenderer; +import com.tagtraum.perf.gcviewer.renderer.FullGCLineRenderer; +import com.tagtraum.perf.gcviewer.renderer.GCRectanglesRenderer; +import com.tagtraum.perf.gcviewer.renderer.GCTimesRenderer; +import com.tagtraum.perf.gcviewer.renderer.IncLineRenderer; +import com.tagtraum.perf.gcviewer.renderer.InitialMarkLevelRenderer; +import com.tagtraum.perf.gcviewer.renderer.PolygonChartRenderer; +import com.tagtraum.perf.gcviewer.renderer.TotalHeapRenderer; +import com.tagtraum.perf.gcviewer.renderer.TotalTenuredRenderer; +import com.tagtraum.perf.gcviewer.renderer.TotalYoungRenderer; +import com.tagtraum.perf.gcviewer.renderer.UsedHeapRenderer; +import com.tagtraum.perf.gcviewer.renderer.UsedTenuredRenderer; +import com.tagtraum.perf.gcviewer.renderer.UsedYoungRenderer; +import com.tagtraum.perf.gcviewer.util.TimeFormat; + /** * Graphical chart of the gc file. It contains the chart and all rulers surrounding it but not * the model details on the right side. @@ -50,7 +82,7 @@ public class ModelChartImpl extends JScrollPane implements ModelChart, ChangeLis private TimeOffsetPanel timeOffsetPanel; private int lastViewPortWidth = 0; - public ModelChartImpl() { + public ModelChartImpl(final GCViewerGui gui) { super(); this.model = new GCModel(true); this.chart = new Chart(); @@ -186,6 +218,7 @@ else if (model.hasCorrectTimestamp()) { } } }); + this.addMouseWheelListener(new ZoomMouseListener(gui, this)); } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/SimpleChartRenderer.java b/src/main/java/com/tagtraum/perf/gcviewer/SimpleChartRenderer.java index a5fe3860..3a2c6aa4 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/SimpleChartRenderer.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/SimpleChartRenderer.java @@ -17,7 +17,7 @@ public void render(GCModel model, String chartFilePath) throws IOException { GCPreferences gcPreferences = new GCPreferences(); gcPreferences.load(); - final ModelChartImpl pane = new ModelChartImpl(); + final ModelChartImpl pane = new ModelChartImpl(null); pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); pane.setModel(model, gcPreferences); diff --git a/src/main/java/com/tagtraum/perf/gcviewer/action/ZoomMouseListener.java b/src/main/java/com/tagtraum/perf/gcviewer/action/ZoomMouseListener.java new file mode 100644 index 00000000..2f2e0811 --- /dev/null +++ b/src/main/java/com/tagtraum/perf/gcviewer/action/ZoomMouseListener.java @@ -0,0 +1,48 @@ +package com.tagtraum.perf.gcviewer.action; + +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; + +import com.tagtraum.perf.gcviewer.GCViewerGui; +import com.tagtraum.perf.gcviewer.ModelChartImpl; + +/** + * @author Serafin Sedano + */ +public class ZoomMouseListener implements MouseWheelListener +{ + private final GCViewerGui gui; + + private ModelChartImpl chart; + + public ZoomMouseListener(GCViewerGui gui, final ModelChartImpl chart) + { + this.gui = gui; + this.chart = chart; + } + + /* + * (non-Javadoc) + * @see java.awt.event.MouseWheelListener#mouseWheelMoved(java.awt.event.MouseWheelEvent) + */ + @Override + public void mouseWheelMoved(MouseWheelEvent e) + { + // In OSX track pad horizontal scrolls yields true + // In *nix shift zoom is horizontal scroll + if(e.isShiftDown()) + return; + + double factor = 1d; + if (e.getWheelRotation() > 0) + { + factor = chart.getScaleFactor() / 1.1d; + } + else + { + factor = chart.getScaleFactor() * 1.1d; + } + // The Listener does the magic + gui.setZoomValue(factor); + } +} diff --git a/src/test/java/com/tagtraum/perf/gcviewer/ModelChartImplTest.java b/src/test/java/com/tagtraum/perf/gcviewer/ModelChartImplTest.java index 9af43b98..55e051dd 100644 --- a/src/test/java/com/tagtraum/perf/gcviewer/ModelChartImplTest.java +++ b/src/test/java/com/tagtraum/perf/gcviewer/ModelChartImplTest.java @@ -34,7 +34,7 @@ public class ModelChartImplTest { @Theory public void shouldShowOrNotDateStampAccordingToModelAndSettings(TestCase testCase) throws Exception { //given - ModelChartImpl modelChart = new ModelChartImpl(); + ModelChartImpl modelChart = new ModelChartImpl(null); GCPreferences preferences = new GCPreferences(); GCModel gcModel = Mockito.mock(GCModel.class); Mockito.when(gcModel.hasDateStamp()).thenReturn(testCase.hasDateStamp());