[Jrisk-cvs] SF.net SVN: domination-code:[2600] Domination/swingUI /src/net/yura
Brought to you by:
yuranet
|
From: <yu...@us...> - 2024-12-23 12:38:14
|
Revision: 2600
http://sourceforge.net/p/domination/code/2600
Author: yuranet
Date: 2024-12-23 12:38:11 +0000 (Mon, 23 Dec 2024)
Log Message:
-----------
show mem graph
Modified Paths:
--------------
Domination/swingUI/src/net/yura/domination/ui/swinggui/SwingGUIPanel.java
Added Paths:
-----------
Domination/swingUI/src/net/yura/swing/HeapView.java
Modified: Domination/swingUI/src/net/yura/domination/ui/swinggui/SwingGUIPanel.java
===================================================================
--- Domination/swingUI/src/net/yura/domination/ui/swinggui/SwingGUIPanel.java 2024-12-18 17:32:15 UTC (rev 2599)
+++ Domination/swingUI/src/net/yura/domination/ui/swinggui/SwingGUIPanel.java 2024-12-23 12:38:11 UTC (rev 2600)
@@ -67,6 +67,7 @@
import net.yura.domination.guishared.StatsPanel;
import net.yura.domination.engine.translation.TranslationBundle;
import net.yura.domination.tools.mapeditor.MapEditor;
+import net.yura.swing.HeapView;
/**
* <p> Swing GUI Main Frame </p>
@@ -1089,6 +1090,7 @@
gc.setActionCommand("gc");
gc.addActionListener(this);
+ HeapView hv = new HeapView();
toolbarDebug.add(tdSaveDebug);
@@ -1101,6 +1103,7 @@
toolbarDebug.add(cr);
toolbarDebug.addSeparator();
toolbarDebug.add(gc);
+ toolbarDebug.add(hv);
toolbarDebug.setFloatable(false);
Added: Domination/swingUI/src/net/yura/swing/HeapView.java
===================================================================
--- Domination/swingUI/src/net/yura/swing/HeapView.java (rev 0)
+++ Domination/swingUI/src/net/yura/swing/HeapView.java 2024-12-23 12:38:11 UTC (rev 2600)
@@ -0,0 +1,433 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 net.yura.swing;
+
+import java.awt.AWTEvent;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Path2D;
+import java.awt.geom.Rectangle2D;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.prefs.Preferences;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JComponent;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
+import javax.swing.Timer;
+import javax.swing.UIManager;
+
+/**
+ * Implements a widget to show the current heap size / max and to trigger a manual GC.
+ * Appearance can be customized using the following properties in the LAF
+ * <ul>
+ * <li> nb.heapview.background - Color of widget background
+ * <li> nb.heapview.foreground - Color of text
+ * <li> nb.heapview.chart - Color of area chart
+ * <li> nb.heapview.highlight - Color of outline around the text, to provide a contrast against
+ * the chart (may have a non-opaque alpha value)
+ * </ul>
+ * @author sky, radim, peter
+ */
+public class HeapView extends JComponent {
+
+ private static final boolean AUTOMATIC_REFRESH = System.getProperty("org.netbeans.log.startup") == null;
+
+ /*
+ * How often the display is updated.
+ */
+ private static final int TICK = 1500;
+
+ /**
+ * Foreground color for the chart.
+ */
+ private static final Color CHART_COLOR;
+
+ /**
+ * Color for text.
+ */
+ private static final Color TEXT_COLOR;
+
+ /**
+ * Color for an outline around the text.
+ */
+ private static final Color OUTLINE_COLOR;
+
+ /**
+ * Color for the background.
+ */
+ private static final Color BACKGROUND_COLOR;
+
+ /**
+ * Number of samples to retain in history.
+ */
+ private static final int GRAPH_COUNT = 100;
+
+ /**
+ * Key for the Show Text preference.
+ */
+ private static final String SHOW_TEXT = "showText";
+
+ static {
+ //init colors
+ Color c = UIManager.getColor("nb.heapview.chart"); //NOI18N
+ if (null == c) {
+ c = new Color(0x2E90E8);
+ }
+ CHART_COLOR = c;
+
+ c = UIManager.getColor("nb.heapview.foreground"); //NOI18N
+ if (null == c) {
+ c = Color.DARK_GRAY;
+ }
+ TEXT_COLOR = c;
+
+ c = UIManager.getColor("nb.heapview.background"); //NOI18N
+ if (null == c) {
+ c = new Color(0xCEDBE6);
+ }
+ BACKGROUND_COLOR = c;
+
+ c = UIManager.getColor("nb.heapview.highlight"); //NOI18N
+ if (null == c) {
+ c = new Color(BACKGROUND_COLOR.getRed(),
+ BACKGROUND_COLOR.getGreen(),
+ BACKGROUND_COLOR.getBlue(),
+ 192);
+ }
+ OUTLINE_COLOR = c;
+ }
+
+ /**
+ * MessageFormat used to generate text.
+ */
+ private final MessageFormat format;
+
+ /**
+ * Data for the graph as a percentage of the heap used.
+ * It is a circular buffer.
+ */
+ private final long[] graph = new long[GRAPH_COUNT];
+
+ /**
+ * Index into graph for the next tick.
+ */
+ private int graphIndex;
+
+ /**
+ * Last total heap size.
+ */
+ private long lastTotal;
+
+ /**
+ * Timer used to update data.
+ */
+ private Timer updateTimer;
+
+ /**
+ * Max width needed to display 999.9/999.9MB. Used to calculate pref size.
+ */
+ private int maxTextWidth;
+
+ /**
+ * Current text being displayed.
+ */
+ private String heapSizeText;
+
+
+ public HeapView() {
+ format = new MessageFormat("{0,choice,0#{0,number,0.0}|999<{0,number,0}}/{1,choice,0#{1,number,0.0}|999<{1,number,0}}MB");
+ heapSizeText = "";
+ // Enable mouse events. This is the equivalent to adding a mouse
+ // listener.
+ enableEvents(AWTEvent.MOUSE_EVENT_MASK);
+ //setToolTipText(NbBundle.getMessage(GarbageCollectAction.class, "CTL_GC"));
+ setToolTipText("Click to force garbage collection");
+ updateUI();
+ }
+
+ /**
+ * Updates the look and feel for this component.
+ */
+ @Override
+ public void updateUI() {
+ Font f = UIManager.getFont("Label.font");
+ setFont(f);
+ /* Setting this true seems to cause some painting artifacts on 150% scaling, as we don't
+ always manage to fill every device pixel with the background color. So leave it off. */
+ setOpaque(false);
+ }
+
+ /**
+ * Sets whether the text displaying the heap size should be shown. The
+ * default is true.
+ *
+ * @param showText whether the text displaying the heap size should be
+ * shown.
+ */
+ public void setShowText(boolean showText) {
+ prefs().putBoolean(SHOW_TEXT, showText);
+ repaint();
+ }
+
+ /**
+ * Returns whether the text displaying the heap size should be shown.
+ *
+ * @return whether the text displaying the heap size should be shown
+ */
+ public boolean getShowText() {
+ return prefs().getBoolean(SHOW_TEXT, true);
+ }
+
+ /**
+ * Sets the font used to display the heap size.
+ *
+ * @param font the font used to display the heap size
+ */
+ @Override
+ public void setFont(Font font) {
+ super.setFont(font);
+ updateTextWidth();
+ }
+
+ // Called by GarbageCollectAction
+ Dimension heapViewPreferredSize() {
+ Dimension size = new Dimension(maxTextWidth + 8, getFontMetrics(
+ getFont()).getHeight() + 8);
+ return size;
+ }
+
+ private Preferences prefs() {
+ //return NbPreferences.forModule(HeapView.class);
+ return Preferences.userNodeForPackage(HeapView.class);
+ }
+
+ /**
+ * Recalculates the width needed to display the heap size string.
+ */
+ private void updateTextWidth() {
+ String maxString = format.format(new Object[]{888.8f, 888.8f});
+ maxTextWidth = getFontMetrics(getFont()).stringWidth(maxString) + 4;
+ }
+
+ /**
+ * Processes a mouse event.
+ *
+ * @param e the MouseEvent
+ */
+ @Override
+ protected void processMouseEvent(MouseEvent e) {
+ super.processMouseEvent(e);
+ if (!e.isConsumed()) {
+ if (e.isPopupTrigger()) {
+ // Show a popup allowing to configure the various options
+ showPopup(e.getX(), e.getY());
+ }
+ }
+
+ if (e.getID() == MouseEvent.MOUSE_CLICKED
+ && SwingUtilities.isLeftMouseButton(e)
+ && e.getClickCount() == 1) {
+ // Trigger a gc
+ //GarbageCollectAction.get(GarbageCollectAction.class).performAction();
+ System.gc();
+ }
+ }
+
+ /**
+ * Shows a popup at the specified location that allows you to configure the
+ * various options.
+ */
+ private void showPopup(int x, int y) {
+ JPopupMenu popup = new JPopupMenu();
+ //JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem(NbBundle.getMessage(HeapView.class, "LBL_ShowText"));
+ JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem("Show Text");
+ cbmi.setSelected(getShowText());
+ cbmi.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ setShowText(((JCheckBoxMenuItem) e.getSource()).
+ isSelected());
+ }
+ });
+ popup.add(cbmi);
+ popup.show(this, x, y);
+ }
+
+ /**
+ * Paints the component.
+ */
+ @Override
+ protected void paintComponent(Graphics g) {
+ super.paintComponent(g);
+ int width = getWidth();
+ int height = getHeight();
+
+ if (width > 0 && height > 0) {
+ startTimerIfNecessary();
+ Graphics2D g2 = (Graphics2D) g.create();
+ try {
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
+ g2.clipRect(0, 0, width, height);
+ // Draw background.
+ g2.setColor(BACKGROUND_COLOR);
+ g2.fillRect(0, 0, width, height);
+ // Draw samples
+ g2.setColor(CHART_COLOR);
+ paintSamples(g2, width, height);
+ // Draw text if enabled
+ if (getShowText()) {
+ paintText(g2, width, height);
+ }
+ } finally {
+ g2.dispose();
+ }
+ } else {
+ stopTimerIfNecessary();
+ }
+ }
+
+ /**
+ * Renders the text using an optional drop shadow.
+ */
+ private void paintText(Graphics2D g, int w, int h) {
+ Font font = getFont();
+ String text = getHeapSizeText();
+ GlyphVector gv = font.createGlyphVector(g.getFontRenderContext(), text);
+ FontMetrics fm = g.getFontMetrics(font);
+ Shape outline = gv.getOutline();
+ Rectangle2D bounds = outline.getBounds2D();
+ double x = Math.max(0, (w - bounds.getWidth()) / 2.0);
+ double y = h / 2.0 + fm.getAscent() / 2.0 - 2.0;
+ AffineTransform oldTransform = g.getTransform();
+ g.translate(x, y);
+ g.setColor(OUTLINE_COLOR);
+ g.setStroke(new BasicStroke(2.5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+ g.draw(outline);
+ g.setColor(TEXT_COLOR);
+ g.fill(outline);
+ g.setTransform(oldTransform);
+ }
+
+ private String getHeapSizeText() {
+ return heapSizeText;
+ }
+
+ /**
+ * Invoked when component removed from a heavy weight parent. Stops the
+ * timer.
+ */
+ @Override
+ public void removeNotify() {
+ super.removeNotify();
+ stopTimerIfNecessary();
+ }
+
+ /**
+ * Restarts the timer.
+ */
+ private void startTimerIfNecessary() {
+ if (!AUTOMATIC_REFRESH) {
+ return;
+ }
+ if (updateTimer == null) {
+ updateTimer = new Timer(TICK, new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ update();
+ }
+ });
+ updateTimer.setRepeats(true);
+ updateTimer.start();
+ }
+ }
+
+ /**
+ * Stops the timer.
+ */
+ private void stopTimerIfNecessary() {
+ if (updateTimer != null) {
+ updateTimer.stop();
+ updateTimer = null;
+ lastTotal = 0;
+ Arrays.fill(graph, 0);
+ heapSizeText = "";
+ }
+ }
+
+ /**
+ * Invoked when the update timer fires. Updates the necessary data
+ * structures and triggers repaints.
+ */
+ private void update() {
+ if (isShowing()) {
+ Runtime r = Runtime.getRuntime();
+ long total = r.totalMemory();
+ long used = total - r.freeMemory();
+ graph[graphIndex] = used;
+ lastTotal = total;
+ ++graphIndex;
+ if (graphIndex >= GRAPH_COUNT) {
+ graphIndex = 0;
+ }
+ heapSizeText = format.format(
+ new Object[]{(double) used / (1024.0 * 1024.0), (double) total / (1024.0 * 1024.0)});
+ repaint();
+ } else {
+ // Either we've become invisible, or one of our ancestors has.
+ // Stop the timer and bale. Next paint will trigger timer to
+ // restart.
+ stopTimerIfNecessary();
+ }
+ }
+
+ /**
+ * Draw the graph with the heap samples. It is a simple area chart.
+ *
+ * @param g Where to draw
+ * @param width The width of the chart
+ * @param height The height of the chart
+ */
+ private void paintSamples(Graphics2D g, int width, int height) {
+ Path2D path = new Path2D.Double();
+ path.moveTo(0, height);
+ for (int i = 0; i < GRAPH_COUNT; ++i) {
+ int index = (i + graphIndex) % GRAPH_COUNT;
+ double x = (double) i / (double) (GRAPH_COUNT - 1) * (double) width;
+ double y = (double) height * (1.0 - (double) graph[index] / (double) lastTotal);
+ path.lineTo(x, y);
+ }
+ path.lineTo(width, height);
+ path.closePath();
+ g.fill(path);
+ }
+}
+
|