Mercurial > hg > release > thermostat-1.4
changeset 1726:df0b23875ffb
Backport: Improve treemap zoom out
review-thread: http://icedtea.classpath.org/pipermail/thermostat/2015-August/015378.html
reviewed-by: jerboaa
PR2586
line wrap: on
line diff
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapIconResources.java Wed Aug 19 11:41:51 2015 +0200 +++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapIconResources.java Thu Aug 20 14:12:33 2015 +0200 @@ -49,6 +49,10 @@ public static final String PIN_MASK = "com/redhat/thermostat/vm/heap/analysis/client/core/pin_mask.png"; public static final String TRIGGER_HEAP_DUMP = "com/redhat/thermostat/vm/heap/analysis/client/core/take_dump.png"; + public static final String BREADCRUMB_HEAD = "com/redhat/thermostat/vm/heap/analysis/client/swing/breadcrumb_head.png"; + public static final String BREADCRUMB_BODY = "com/redhat/thermostat/vm/heap/analysis/client/swing/breadcrumb_body.png"; + public static final String BREADCRUMB_TAIL = "com/redhat/thermostat/vm/heap/analysis/client/swing/breadcrumb_tail.png"; + private static Map<String, IconDescriptor> icons = new HashMap<>(); public synchronized static IconDescriptor getIcon(String path) {
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/locale/LocaleResources.java Wed Aug 19 11:41:51 2015 +0200 +++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/locale/LocaleResources.java Thu Aug 20 14:12:33 2015 +0200 @@ -80,6 +80,9 @@ LIST_DUMPS_ACTION, HEAP_DUMP_SECTION_TREEMAP, + ZOOM_IN, + ZOOM_OUT, + ZOOM_FULL, ; static final String RESOURCE_BUNDLE = "com.redhat.thermostat.vm.heap.analysis.client.locale.strings";
--- a/vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/locale/strings.properties Wed Aug 19 11:41:51 2015 +0200 +++ b/vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/locale/strings.properties Thu Aug 20 14:12:33 2015 +0200 @@ -36,4 +36,8 @@ DUMPS_LIST = Available Dumps HEAP_DUMP_IN_PROGRESS = dumping... HEAP_DUMP_LOADING_IN_PROGRESS = loading... -PROCESS_EXITED = Process exited. \ No newline at end of file +PROCESS_EXITED = Process exited. + +ZOOM_IN = Zoom in the selected item. Try also with a double click +ZOOM_OUT = Zoom out the view. Try also with a left click +ZOOM_FULL = Restore the original zoom level. Try also with a mouse wheel click
Binary file vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/swing/breadcrumb_body.png has changed
Binary file vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/swing/breadcrumb_head.png has changed
Binary file vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/swing/breadcrumb_tail.png has changed
--- a/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HistogramConverter.java Wed Aug 19 11:41:51 2015 +0200 +++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HistogramConverter.java Thu Aug 20 14:12:33 2015 +0200 @@ -67,7 +67,7 @@ * @return the resulting tree */ public static TreeMapNode convertToTreeMap(ObjectHistogram histrogram) { - TreeMapNode root = new TreeMapNode("", 0); + TreeMapNode root = new TreeMapNode("", 0); List<HistogramRecord> records = new ArrayList<>(); records.addAll(histrogram.getHistogram()); @@ -104,8 +104,7 @@ String nodeId = className.split(SPLIT_REG_EXP)[0]; - TreeMapNode child = lastProcessed.searchNodeByLabel(nodeId); - + TreeMapNode child = searchNode(lastProcessed, nodeId); if (child == null) { child = new TreeMapNode(nodeId, 0); lastProcessed.addChild(child); @@ -130,6 +129,16 @@ } } + private static TreeMapNode searchNode(TreeMapNode root, String nodeId) { + List<TreeMapNode> nodes = root.getChildren(); + for (TreeMapNode node : nodes) { + if (node.getLabel().equals(nodeId)) { + return node; + } + } + return null; + } + /** * This method calcs the real weights using a bottom-up traversal. From leaves, * weights are passed to parent nodem which will have as weight the sum of
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapBreadcrumb.java Thu Aug 20 14:12:33 2015 +0200 @@ -0,0 +1,306 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.heap.analysis.client.swing.internal; + +import java.awt.Font; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.font.FontRenderContext; +import java.util.LinkedList; +import java.util.Objects; +import java.util.Stack; + +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.UIManager; + +import com.redhat.thermostat.client.swing.components.Icon; +import com.redhat.thermostat.vm.heap.analysis.client.core.HeapIconResources; + +/** + * This object creates a breadcrumb navigation bar used to trace + * {@link TreeMapComponent} objects' state. + */ +public class TreeMapBreadcrumb extends JComponent implements TreeMapObserver { + + private static final long serialVersionUID = 1L; + + /** + * Font used by bradcrumb items. + */ + private Font FONT = (Font) UIManager.get("thermostat-default-font"); + + /** + * Stack containing all items part of the breadcrumb. + */ + private Stack<BreadcrumbItem> items; + + /** + * The TreeMap object to interact with. + */ + private TreeMapComponent treemap; + + /** + * Constructor. Creates a breadcumbs navigation bar with the starting + * element and register itself as observer to the given treemap. + * + * @param start the treemap's root. + */ + public TreeMapBreadcrumb(TreeMapComponent treemap, TreeMapNode start) { + super(); + setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + this.items = new Stack<>(); + this.treemap = Objects.requireNonNull(treemap); + this.treemap.register(this); + buildBreadcrumb(start); + } + + + /** + * Builds the breadcrumb using the nodes'ancestors. + * @param node the tree's branch to represent ad breadcrumb bar. + */ + public void buildBreadcrumb(TreeMapNode node) { + LinkedList<TreeMapNode> nodes = node.getAncestors(); + + while (!nodes.isEmpty()) { + BreadcrumbItem item = new BreadcrumbItem(nodes.removeLast()); + items.push(item); + add(item); + } + // the first element has no tail + items.get(0).setAsFirst(); + + //the last element has no head + items.peek().setAsLast(); + } + + + @Override + public void notifySelection(TreeMapNode node) { + // do nothing + } + + @Override + public void notifyZoomIn(TreeMapNode node) { + items.clear(); + removeAll(); + buildBreadcrumb(node); + } + + @Override + public void notifyZoomOut() { + this.remove(items.pop()); + items.peek().setAsLast(); + items.peek().repaint(); + } + + @Override + public void notifyZoomFull() { + items.clear(); + this.removeAll(); + BreadcrumbItem item = new BreadcrumbItem(treemap.getTreeMapRoot()); + item.setAsFirst(); + item.setAsLast(); + items.push(item); + this.add(item); + } + + + + /** + * This class allows to create a single item in a breadcrumb object. + * This component has 3 {@link JLabel}s which contain the images needed + * to draw an arrow. + * _____ + * > |_____| > + * | | | + * tail body head + * + */ + class BreadcrumbItem extends JComponent { + + private static final long serialVersionUID = 1L; + + private final String ROOT_TEXT = "root"; + + private JLabel tail; + private JLabel body; + private JLabel head; + + /** + * The node this items represents. + */ + private TreeMapNode node; + + /** + * The constructor creates a complete item, including both tail and head + * @param node + */ + public BreadcrumbItem(final TreeMapNode node) { + super(); + this.node = node; + this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + initComponent(); + + /** + * Simulate the click effect increasing and reducing the font size + */ + this.addMouseListener(new MouseAdapter() { + + @Override + public void mouseReleased(MouseEvent arg0) { + increaseFont(body, 2); + } + + @Override + public void mousePressed(MouseEvent arg0) { + increaseFont(body, -2); + } + + @Override + public void mouseClicked(MouseEvent arg0) { + treemap.zoomIn(node); + } + }); + } + + + /** + * Increases the given component's font size. + * @param comp the component which edit the font size to. + * @param increment value of the increment. Negative values reduce the + * font size. + */ + private void increaseFont(JComponent comp, int increment) { + Font f = comp.getFont(); + int newSize = f.getSize() + increment; + f = new Font(f.getName(), f.getStyle(), newSize); + comp.setFont(f); + comp.repaint(); + } + + private void initComponent() { + initTail(); + initBody(); + initHead(); + } + + + private void initTail() { + tail = new JLabel(); + tail.setIcon(new Icon(HeapIconResources.getIcon(HeapIconResources.BREADCRUMB_TAIL))); + this.add(tail); + } + + private void initHead() { + head = new JLabel(); + head.setIcon(new Icon(HeapIconResources.getIcon(HeapIconResources.BREADCRUMB_HEAD))); + this.add(head); + } + + private void initBody() { + body = new JLabel(); + body.setFont(FONT); + body.setHorizontalTextPosition(JLabel.CENTER); + body.setText(node.getLabel()); + adaptIcon(body, new Icon(HeapIconResources.getIcon(HeapIconResources.BREADCRUMB_BODY))); + this.add(body); + } + + + public TreeMapNode getNode() { + return this.node; + } + + /** + * Remove the tail of his breadcrumb item. + */ + public void setAsFirst() { + this.remove(tail); + this.tail = null; + this.body.setText(ROOT_TEXT); + adaptIcon(body, new Icon(HeapIconResources.getIcon(HeapIconResources.BREADCRUMB_BODY))); + } + + /** + * Remove the head of his breadcrumb item. + */ + public void setAsLast() { + this.remove(head); + this.head = null; + } + + /** + * Sets the text of this item, which is placed in the body. + * @param text + */ + public void setText(String text) { + body.setText(text); + } + + public int getHeight() { + return body.getPreferredSize().height; + } + } + + /** + * Calculates the labels' text size in order to scale the given image + * and to apply to it. + */ + private void adaptIcon(JLabel label, ImageIcon icon) { + Rectangle fontArea; + try { + fontArea = label.getFont().getStringBounds(label.getText(), + new FontRenderContext(label.getFont().getTransform(), + false, false)).getBounds(); + + } catch (NullPointerException npe) { + fontArea = label.getBounds(); + } + + Image img = icon.getImage(); + Image newimg = img.getScaledInstance(fontArea.getBounds().width + 10, + img.getHeight(null), java.awt.Image.SCALE_SMOOTH); + icon = new ImageIcon(newimg); + label.setIcon(icon); + } +}
--- a/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapComponent.java Wed Aug 19 11:41:51 2015 +0200 +++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapComponent.java Thu Aug 20 14:12:33 2015 +0200 @@ -53,6 +53,9 @@ import java.awt.event.MouseListener; import java.awt.font.FontRenderContext; import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; import java.util.Objects; import java.util.Stack; @@ -163,6 +166,11 @@ private static Comp lastClicked; /** + * List of objects observing this. + */ + private List<TreeMapObserver> observers; + + /** * Constructor which creates a TreeMapComponent by an histogram object. * @param histogram the histogram to represent as tree map. */ @@ -187,6 +195,7 @@ lastDim = getSize(); this.zoomStack = new Stack<>(); this.zoomStack.push(this.tree); + this.observers = new ArrayList<>(); // assign a rectangle to the tree's root in order to process the tree. Rectangle2D.Double area = new Rectangle2D.Double(0, 0, d.width, d.height); @@ -333,7 +342,7 @@ Dimension newDim = container.getSize(); if (isChangedSize(newDim)) { - redrawTreeMap(); + redrawTreeMap(tree); } } } @@ -379,7 +388,8 @@ * This method recalculates and redraws the TreeMap in according to the size * of this component and the actual {@link TreeMapNode} object. */ - private void redrawTreeMap() { + private void redrawTreeMap(TreeMapNode newRoot) { + tree = newRoot; Rectangle2D.Double newArea = tree.getRectangle(); // give to the root node the size of this object so it can be recalculated newArea.width = getSize().width; @@ -392,27 +402,33 @@ drawTreeMap(tree); } - /** - * Zoom the TreeMap on the given node. - * @param node the new TreeMap's root. - */ + boolean isZoomInEnabled(TreeMapNode node) { + return !(node == null + || node.equals(this.tree) + || node.isLeaf()); + } + public void zoomIn(TreeMapNode node) { - if (node != null && node != this.tree && !zoomStack.contains(node)) { - zoomStack.push(node); - tree = node; - redrawTreeMap(); + if (isZoomInEnabled(node)) { + fillZoomStack(node.getAncestors()); + redrawTreeMap(node); + notifyZoomInToObservers(zoomStack.peek()); } } - /** - * Zoom out the view to the last zoom level, until the original root is - * reached. - */ + private void fillZoomStack(LinkedList<TreeMapNode> ancestors) { + zoomStack.clear(); + while (!ancestors.isEmpty()) { + zoomStack.push(ancestors.removeLast()); + } + } + public void zoomOut() { + // if the actual root element is not the tree's original root if (zoomStack.size() > 1) { zoomStack.pop(); - tree = zoomStack.peek(); - redrawTreeMap(); + redrawTreeMap(zoomStack.peek()); + notifyZoomOutToObservers(); } } @@ -422,12 +438,69 @@ public void zoomFull() { if (zoomStack.size() > 1) { clearZoomCallsStack(); - tree = zoomStack.peek(); - redrawTreeMap(); + redrawTreeMap(zoomStack.peek()); + notifyZoomFullToObservers(); + } + } + + /** + * Add the object in input to the list of registered objects to this TreeMap. + * @param observer the Notifiable object to register to this object. + */ + public void register(TreeMapObserver observer) { + this.observers.add(observer); + } + + /** + * Remove the object in input from the list of registered objects to this TreeMap. + * @param observer the Notifiable object to unregister from this object. + */ + public void unregister(TreeMapObserver observer) { + this.observers.remove(observer); + } + /** + * Notify observers that an object in the TreeMap has been selected. + * @param comp the selected component. + */ + private void notifySelectionToObservers(TreeMapNode node) { + for (TreeMapObserver observer : observers) { + observer.notifySelection(node); } } /** + * Notify observers that TreeMap has been zoomed. + * @param zoomedComponent + */ + private void notifyZoomInToObservers(TreeMapNode node) { + for (TreeMapObserver observer : observers) { + observer.notifyZoomIn(node); + } + } + + /** + * Notify observers that TreeMap has been zoomed. + * @param zoomedComponent + */ + private void notifyZoomOutToObservers() { + for (TreeMapObserver observer : observers) { + observer.notifyZoomOut(); + } + } + + /** + * Notify observers that TreeMap has been zoomed. + * @param zoomedComponent + */ + private void notifyZoomFullToObservers() { + for (TreeMapObserver observer : observers) { + observer.notifyZoomFull(); + } + } + + + + /** * Returns the list of zoom operation calls. * @return the stack that holds the zoom calls. */ @@ -640,19 +713,17 @@ if (SwingUtilities.isLeftMouseButton(e)) { selectComp(); } - // two left click: zoom-in - // two right click: zoom-out - // two middle click: zoom full - if (e.getClickCount() == 2) { - if (SwingUtilities.isLeftMouseButton(e)) { - if (!getNode().isLeaf()) { - zoomIn(getNode()); - } - } else if (SwingUtilities.isRightMouseButton(e)) { - zoomOut(); - } else { - zoomFull(); - } + // double left click to zoom in (on non-leaf nodes only) + if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e)) { + zoomIn(getNode()); + } + // one right click to zoom out + if (SwingUtilities.isRightMouseButton(e)) { + zoomOut(); + } + // one middle click to reset zoom + if (SwingUtilities.isMiddleMouseButton(e)) { + zoomFull(); } } }; @@ -712,6 +783,7 @@ setColor(getColor().darker()); } repaint(); + notifySelectionToObservers(node); } } }
--- a/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapNode.java Wed Aug 19 11:41:51 2015 +0200 +++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapNode.java Thu Aug 20 14:12:33 2015 +0200 @@ -42,6 +42,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -291,27 +292,6 @@ "; rectangle=" + rectangle.getBounds() + "]"; } - - /** - * Search into the tree the node with id = key. - * @param key the id of the node to search. - * @return the node of exists, else null. - */ - public TreeMapNode searchNodeByLabel(String key) { - if (this.getLabel().equals(key)) { - return this; - } - - TreeMapNode result = null; - for (TreeMapNode child : getChildren()) { - result = child.searchNodeByLabel(key) ; - if (result != null) { - return result; - } - } - return result; - } - /** * Return the weight of this object. In case of allowNonPositiveWeight is * set to false and the weight is 0, less than 0 or not a number @@ -451,4 +431,18 @@ }; Collections.sort(nodes, c); } + + /** + * Return the list of ancestors node of this object. The first one is this + * node itself, the last one the root. + * @return a list of ancestors nodes. + */ + public LinkedList<TreeMapNode> getAncestors() { + LinkedList<TreeMapNode> toReturn = new LinkedList<TreeMapNode>(); + TreeMapNode tmp = this; + do { + toReturn.add(tmp); + } while ((tmp = tmp.getParent()) != null); + return toReturn; + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapObserver.java Thu Aug 20 14:12:33 2015 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.heap.analysis.client.swing.internal; + +/** + * This interface is used as part of the Observer Design Pattern developed + * for objects who want to be notified about TreeMap's events. + */ +public interface TreeMapObserver { + + /** + * This method inform the Observer object that the object passed as + * argument has been selected. + * + * @param selectedComp the selected component to communicate to + * this Observer object. + */ + public void notifySelection(TreeMapNode node); + + /** + * This method informs objects that a zoom in event has been performed on + * the given node. + * @param node the zoomed node. + */ + public void notifyZoomIn(TreeMapNode node); + + /** + * This method informs objects that a zoom out event has been performed. + */ + public void notifyZoomOut(); + + /** + * This method informs objects that the zoom level has been resetted. + */ + public void notifyZoomFull(); +}
--- a/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapPanel.java Wed Aug 19 11:41:51 2015 +0200 +++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapPanel.java Thu Aug 20 14:12:33 2015 +0200 @@ -36,40 +36,35 @@ package com.redhat.thermostat.vm.heap.analysis.client.swing.internal; +import java.awt.BorderLayout; import java.awt.Component; -import javax.swing.BoxLayout; import javax.swing.JPanel; import com.redhat.thermostat.client.swing.SwingComponent; -import com.redhat.thermostat.shared.locale.Translate; import com.redhat.thermostat.vm.heap.analysis.client.core.HeapTreeMapView; -import com.redhat.thermostat.vm.heap.analysis.client.locale.LocaleResources; import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram; -@SuppressWarnings("serial") public class TreeMapPanel extends HeapTreeMapView implements SwingComponent { - private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); - private final JPanel panel; private TreeMapComponent treeMap; public TreeMapPanel() { panel = new JPanel(); - panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); + panel.setLayout(new BorderLayout()); } @Override public void display(ObjectHistogram histogram) { treeMap = new TreeMapComponent(histogram); - panel.add(treeMap); + panel.add(treeMap, BorderLayout.CENTER); + panel.add(new TreeMapToolbar(treeMap), BorderLayout.NORTH); } @Override public Component getUiComponent() { return panel; } - }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapToolbar.java Thu Aug 20 14:12:33 2015 +0200 @@ -0,0 +1,124 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.heap.analysis.client.swing.internal; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.util.Objects; + +import javax.swing.Box; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.ScrollPaneConstants; + +/** + * This class provides a tool bar containing a {@lnk TreeMapBreadcrumb} object + * and a {@link TreeMapZoomBar} instance to control the state of + * {@link TreeMapComponent} objects. + */ +@SuppressWarnings("serial") +public class TreeMapToolbar extends JComponent { + + /** + * The panel in which objects are placed. + */ + private JPanel contentPane; + + /** + * The scroll pane used to hide breadcrumb's first items. + */ + private JScrollPane scrollPane; + + + public TreeMapToolbar(TreeMapComponent treemap) { + super(); + initComponent(Objects.requireNonNull(treemap)); + } + + + private void initComponent(TreeMapComponent treemap) { + this.setLayout(new BorderLayout()); + + final JPanel breadcrumbPanel = new JPanel(); + breadcrumbPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); + add(breadcrumbPanel, BorderLayout.CENTER); + + JPanel zoomPanel = new JPanel(new FlowLayout()); + // add some empty space between the breadcrumb bar and buttons + zoomPanel.add(Box.createHorizontalStrut(20)); + add(zoomPanel, BorderLayout.EAST); + + TreeMapZoomBar zoomBar = new TreeMapZoomBar(treemap); + zoomPanel.add(zoomBar); + + TreeMapBreadcrumb bc = new TreeMapBreadcrumb(treemap, treemap.getTreeMapRoot()); + + contentPane = new JPanel(new FlowLayout(FlowLayout.LEFT)); + contentPane.add(bc); + + scrollPane = new JScrollPane(contentPane); + scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); + scrollPane.setBorder(null); + + // allows to see always the last elements of the breadcrumb. + scrollPane.getHorizontalScrollBar().addAdjustmentListener(new AdjustmentListener() { + public void adjustmentValueChanged(AdjustmentEvent e) { + e.getAdjustable().setValue(e.getAdjustable().getMaximum()); + } + }); + breadcrumbPanel.add(scrollPane); + + // when the component is resized the new dimension is used to arrange + // the scrollpane, in order to use all available space. + breadcrumbPanel.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent arg0) { + Dimension d = breadcrumbPanel.getSize(); + d.height = 20; + scrollPane.setPreferredSize(d); + } + }); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapZoomBar.java Thu Aug 20 14:12:33 2015 +0200 @@ -0,0 +1,242 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.heap.analysis.client.swing.internal; + +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.Objects; + +import javax.swing.JComponent; +import javax.swing.JLabel; + +import com.redhat.thermostat.client.swing.components.FontAwesomeIcon; +import com.redhat.thermostat.client.swing.components.Icon; +import com.redhat.thermostat.client.ui.Palette; +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.vm.heap.analysis.client.locale.LocaleResources; + +/** + * This class provides a component containing zoom in/out/full buttons which can + * control a {@link TreeMapComponent} object. + */ +public class TreeMapZoomBar extends JComponent implements TreeMapObserver { + + private static final long serialVersionUID = 1L; + + private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); + + private JLabel zoomOut; + private JLabel zoomFull; + private JLabel zoomIn; + + private Color defaultColor = Palette.BLACK.getColor(); + private Color enterColor = Palette.THERMOSTAT_BLU.getColor(); + + /** + * The treemap object to interact with. + */ + private TreeMapComponent treemap; + + /** + * If an item is selected in the treemap, it is stored in order to zoom on + * it if the ZoomIn button is pressed. + */ + private TreeMapNode selectedItem; + + /** + * Constructor. It creates the zoom buttons and registers this object as + * treemap observer. + */ + public TreeMapZoomBar(TreeMapComponent treemap) { + super(); + this.treemap = Objects.requireNonNull(treemap); + initComponent(); + treemap.register(this); + } + + private void initComponent() { + this.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); + createZoomInButton(); + createZoomFullButton(); + createZoomOutButton(); + + /* + * At the beginning no actions can be performed: + * Cannot zoom in because no item is selected; + * cannot zoom out because zoom in hasn't been performed; + * the same for zoom full. + */ + zoomIn.setEnabled(false); + zoomFull.setEnabled(false); + zoomOut.setEnabled(false); + } + + + + private void createZoomInButton() { + zoomIn = new JLabel(); + final Icon baseIcon = new FontAwesomeIcon('\uf065', 15, defaultColor); + final Icon hoverIcon = new FontAwesomeIcon('\uf065', 15, enterColor); + + zoomIn.setIcon(baseIcon); + zoomIn.setToolTipText(t.localize(LocaleResources.ZOOM_IN).getContents()); + + zoomIn.addMouseListener(new MouseAdapter() { + @Override + public void mouseExited(MouseEvent e) { + zoomIn.setIcon(baseIcon); + } + + @Override + public void mouseEntered(MouseEvent e) { + zoomIn.setIcon(hoverIcon); + } + + @Override + public void mouseClicked(MouseEvent arg0) { + if (selectedItem != null) { + treemap.zoomIn(selectedItem); + } + } + }); + + this.add(zoomIn); + } + + private void createZoomOutButton() { + zoomOut = new JLabel(); + + final Icon baseIcon = new FontAwesomeIcon('\uf066', 15, defaultColor); + final Icon hoverIcon = new FontAwesomeIcon('\uf066', 15, enterColor); + + zoomOut.setIcon(baseIcon); + zoomOut.setToolTipText(t.localize(LocaleResources.ZOOM_OUT).getContents()); + zoomOut.addMouseListener(new MouseAdapter() { + @Override + public void mouseExited(MouseEvent e) { + zoomOut.setIcon(baseIcon); + } + + @Override + public void mouseEntered(MouseEvent e) { + zoomOut.setIcon(hoverIcon); + } + + @Override + public void mouseClicked(MouseEvent arg0) { + treemap.zoomOut(); + } + }); + + this.add(zoomOut); + } + + private void createZoomFullButton() { + zoomFull = new JLabel(); + + final Icon baseIcon = new FontAwesomeIcon('\uf03b', 15, defaultColor); + final Icon hoverIcon = new FontAwesomeIcon('\uf03b', 15, enterColor); + + zoomFull.setIcon(baseIcon); + zoomFull.setToolTipText(t.localize(LocaleResources.ZOOM_FULL).getContents()); + zoomFull.addMouseListener(new MouseAdapter() { + @Override + public void mouseExited(MouseEvent e) { + zoomFull.setIcon(baseIcon); + } + + @Override + public void mouseEntered(MouseEvent e) { + zoomFull.setIcon(hoverIcon); + } + + @Override + public void mouseClicked(MouseEvent arg0) { + treemap.zoomFull(); + } + }); + + this.add(zoomFull); + } + + /** + * Changes the buttons state in according to the treemap view. + */ + private void changeState() { + selectedItem = null; + zoomIn.setEnabled(false); + + if (!isRootShown()) { + zoomFull.setEnabled(true); + zoomOut.setEnabled(true); + } else { + zoomFull.setEnabled(false); + zoomOut.setEnabled(false); + } + } + + @Override + public void notifySelection(TreeMapNode node) { + selectedItem = node; + zoomIn.setEnabled(treemap.isZoomInEnabled(node)); + } + + @Override + public void notifyZoomIn(TreeMapNode node) { + changeState(); + } + + @Override + public void notifyZoomOut() { + changeState(); + } + + @Override + public void notifyZoomFull() { + // no actions can be performed + zoomFull.setEnabled(false); + zoomOut.setEnabled(false); + zoomIn.setEnabled(false); + } + + private boolean isRootShown() { + return treemap.getTreeMapRoot() == treemap.getZoomCallsStack().firstElement(); + } + +}
--- a/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HistogramConverterTest.java Wed Aug 19 11:41:51 2015 +0200 +++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HistogramConverterTest.java Thu Aug 20 14:12:33 2015 +0200 @@ -37,8 +37,10 @@ package com.redhat.thermostat.vm.heap.analysis.client.swing.internal; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; + +import java.util.List; import org.junit.Before; import org.junit.Test; @@ -53,15 +55,19 @@ @Before public void setUp() throws Exception { - - /* - * This is the classes structure used for the test and built using histogram + * This is the classes structure used for the test and built using + * histogram. Nodes are compacted at the point of branching + * so for example the node relative to "example2.package1.Class1" is + * still just one node "example2.package1.Class1" but the node relative + * to "com.example1.package1.Class1" branches at "com" so becomes the + * common parent node "com" with children "example1" and "example2", + * and so fort: * * ________com_______ java * / \ | * __example1__ example2 lang - * / \ | | + * / \ | | * package1 package2 package1 Object * / \ | | * Class1 Class2 Class3 Class4 @@ -82,13 +88,16 @@ * Class1 Class2 * */ - final String[] classes = { "com.example1.package1.Class1", "com.example1.package1.Class2", "com.example1.package2.Class3", "com.example2.package1.Class4", - "java.lang.Object" + "example2.package1.Class1", + "java.lang.Object", + "repeat1.repeat1.RepeatClass", + "repeat2.repeat2A.RepeatClass", + "repeat2.repeat2B.RepeatClass", }; histrogram = new ObjectHistogram(); @@ -112,58 +121,64 @@ } } + private static TreeMapNode searchNode(List<TreeMapNode> nodes, String nodeId) { + for (TreeMapNode node : nodes) { + if (node.getLabel().equals(nodeId)) { + return node; + } + } + return null; + } + @Test - public final void testconvertToTreeMap() { + public void testconvertToTreeMap() { TreeMapNode tree = HistogramConverter.convertToTreeMap(histrogram); - - //tree node is the root element, which has an empty label by default - assertEquals(tree.getLabel(), ""); - assertTrue(tree.getChildren().size() == 2); - - - TreeMapNode com = tree.searchNodeByLabel("com"); - assertNotNull(com); - assertEquals(com.getParent(), tree); + List<TreeMapNode> nodes = tree.getChildren(); + assertEquals(5, nodes.size()); + + TreeMapNode node = searchNode(nodes, "com"); + assertNotNull(node); - TreeMapNode java = tree.searchNodeByLabel("java.lang.Object"); - assertNotNull(java); - assertEquals(java.getParent(), tree); + List<TreeMapNode> nodesFromCom = node.getChildren(); + + // example1 and example2 + assertEquals(2, nodesFromCom.size()); + node = searchNode(nodesFromCom, "example1"); + assertNotNull(node); - // com node has 2 children - assertTrue(com.getChildren().size() == 2); + // package2.Class3 and package1 + assertEquals(2, node.getChildren().size()); - TreeMapNode example1 = com.searchNodeByLabel("example1"); - assertNotNull(example1); - assertEquals(example1.getParent(), com); + node = searchNode(node.getChildren(), "package2.Class3"); + assertNotNull(node); + assertTrue(node.getChildren().isEmpty()); - //example2 subtree has been collapsed in example2 node - TreeMapNode example2 = com.searchNodeByLabel("example2.package1.Class4"); - assertNotNull(example2); - assertEquals(example2.getParent(), com); + node = searchNode(nodes, "java.lang.Object"); + assertNotNull(node); + assertTrue(node.getChildren().isEmpty()); + node = searchNode(nodes, "example2.package1.Class1"); + assertNotNull(node); + assertTrue(node.getChildren().isEmpty()); - assertTrue(example1.getChildren().size() == 2); - - //class3 node has been collapsed in package2 node - TreeMapNode package2 = example1.searchNodeByLabel("package2.Class3"); - assertNotNull(package2); - assertEquals(package2.getParent(), example1); - + // now on to the "repeat1.repeat1.RepeatClass" bunch + node = searchNode(nodes, "repeat1.repeat1.RepeatClass"); + assertNotNull(node); + assertTrue(node.getChildren().isEmpty()); - TreeMapNode package1 = example1.searchNodeByLabel("package1"); - assertNotNull(package1); - assertEquals(package1.getParent(), example1); - - assertTrue(package1.getChildren().size() == 2); + node = searchNode(nodes, "repeat2"); + assertNotNull(node); + assertEquals(2, node.getChildren().size()); - TreeMapNode class1 = package1.searchNodeByLabel("Class1"); - assertNotNull(class1); - assertTrue(class1.getChildren().isEmpty()); + List<TreeMapNode> nodesFromRepeat2 = node.getChildren(); + node = searchNode(nodesFromRepeat2, "repeat2A.RepeatClass"); + assertNotNull(node); + assertTrue(node.getChildren().isEmpty()); - TreeMapNode class2 = package1.searchNodeByLabel("Class2"); - assertNotNull(class2); - assertTrue(class2.getChildren().isEmpty()); + node = searchNode(nodesFromRepeat2, "repeat2B.RepeatClass"); + assertNotNull(node); + assertTrue(node.getChildren().isEmpty()); } } \ No newline at end of file
--- a/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapComponentTest.java Wed Aug 19 11:41:51 2015 +0200 +++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapComponentTest.java Thu Aug 20 14:12:33 2015 +0200 @@ -37,6 +37,7 @@ package com.redhat.thermostat.vm.heap.analysis.client.swing.internal; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.awt.Dimension; @@ -71,7 +72,6 @@ @Test public final void testTreeMapComponent() throws InvocationTargetException, InterruptedException { - SwingUtilities.invokeAndWait(new Runnable() { @Override @@ -124,6 +124,21 @@ } @Test + public final void testIsZoomInEnabled() throws InvocationTargetException, InterruptedException { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + TreeMapComponent treeMap = new TreeMapComponent(tree, dim); + + assertFalse("Should not be able to zoom in on null", treeMap.isZoomInEnabled(null)); + assertFalse("Should not be able to zoom in on root", treeMap.isZoomInEnabled(tree)); + assertTrue("Should be able to zoom in on node 1", treeMap.isZoomInEnabled(node1)); + assertFalse("Should not be able to zoom in on node 2", treeMap.isZoomInEnabled(node2)); + } + }); + } + + @Test public final void testZoomIn() throws InvocationTargetException, InterruptedException { SwingUtilities.invokeAndWait(new Runnable() { @@ -135,7 +150,7 @@ assertEquals(node1, treeMap.getTreeMapRoot()); treeMap.zoomIn(node2); - assertEquals(node2, treeMap.getTreeMapRoot()); + assertEquals(node1, treeMap.getTreeMapRoot()); } }); } @@ -152,9 +167,8 @@ assertEquals(tree, treeMap.getTreeMapRoot()); treeMap.zoomIn(node1); //if zoom out root is tree - treeMap.zoomIn(node2); //if zoom out root is node1 + treeMap.zoomIn(node2); //no-op, cannot zoom on leaf - treeMap.zoomOut(); assertEquals(node1, treeMap.getTreeMapRoot()); treeMap.zoomOut(); @@ -221,4 +235,59 @@ } }); } + + @Test + public final void testObserver() throws InvocationTargetException, InterruptedException { + SwingUtilities.invokeAndWait(new Runnable() { + boolean zoomedIn = false; + boolean zoomedOut = false; + boolean zoomedFull = false; + + TreeMapObserver observer = new TreeMapObserver() { + @Override + public void notifyZoomOut() { + zoomedOut = true; + } + + @Override + public void notifyZoomIn(TreeMapNode node) { + zoomedIn = true; + } + + @Override + public void notifyZoomFull() { + zoomedFull = true; + } + + @Override + public void notifySelection(TreeMapNode node) { + } + }; + + @Override + public void run() { + TreeMapNode child = new TreeMapNode(1); + tree.addChild(child); + TreeMapNode grandchild = new TreeMapNode(1); + child.addChild(grandchild); + + treeMap = new TreeMapComponent(tree, dim); + treeMap.register(observer); + + treeMap.zoomIn(child); + assertTrue("Should have zoomed in on child", zoomedIn); + zoomedIn = false; + + treeMap.zoomIn(grandchild); + assertFalse("Should not have zoomed in on grandchild", zoomedIn); + + treeMap.zoomOut(); + assertTrue("Should have zoomed out", zoomedOut); + + treeMap.zoomIn(child); + treeMap.zoomFull(); + assertTrue("Should have zoomed full", zoomedFull); + } + }); + } }
--- a/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapNodeTest.java Wed Aug 19 11:41:51 2015 +0200 +++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapNodeTest.java Thu Aug 20 14:12:33 2015 +0200 @@ -46,6 +46,7 @@ import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -205,32 +206,6 @@ } @Test - public final void testSearchByLabel() { - TreeMapNode root = new TreeMapNode("root", 0); - - TreeMapNode a = new TreeMapNode("a", 3); - TreeMapNode b = new TreeMapNode("b", 2); - TreeMapNode c = new TreeMapNode("c", 1); - root.addChild(a); - root.addChild(b); - root.addChild(c); - - TreeMapNode aa = new TreeMapNode("aa", 3); - TreeMapNode ab = new TreeMapNode("ab", 3); - TreeMapNode ac = new TreeMapNode("ac", 3); - a.addChild(aa); - a.addChild(ab); - a.addChild(ac); - - assertEquals(aa, root.searchNodeByLabel("aa")); - assertEquals(b, root.searchNodeByLabel("b")); - assertEquals(ac, root.searchNodeByLabel("ac")); - assertEquals(c, root.searchNodeByLabel("c")); - } - - - - @Test public final void testSort() { TreeMapNode n1 = new TreeMapNode(null, 5); @@ -290,4 +265,25 @@ node.setColor(node.getNextColor()); } } + + + @Test + public final void testGetAncestors() { + TreeMapNode node1 = new TreeMapNode(0); + TreeMapNode node2 = new TreeMapNode(0); + TreeMapNode node3 = new TreeMapNode(0); + TreeMapNode node4 = new TreeMapNode(0); + + node1.addChild(node2); + node2.addChild(node3); + node3.addChild(node4); + + LinkedList<TreeMapNode> ancestors = node4.getAncestors(); + + assertEquals(node1, ancestors.get(3)); + assertEquals(node2, ancestors.get(2)); + assertEquals(node3, ancestors.get(1)); + assertEquals(node4, ancestors.get(0)); + } + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapToolbarTest.java Thu Aug 20 14:12:33 2015 +0200 @@ -0,0 +1,90 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.heap.analysis.client.swing.internal; + +import static org.junit.Assert.assertTrue; + +import java.awt.Dimension; +import java.lang.reflect.InvocationTargetException; + +import javax.swing.SwingUtilities; + +import junit.framework.Assert; + +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import com.redhat.thermostat.annotations.internal.CacioTest; + +@Category(CacioTest.class) +public class TreeMapToolbarTest { + + private TreeMapComponent treeMap; + @SuppressWarnings("unused") + private TreeMapToolbar toolbar; + + private static TreeMapNode tree; + private static Dimension dim; + + @Test + public final void testTreeMapToolbar() throws InvocationTargetException, InterruptedException { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + + tree = new TreeMapNode(1); + dim = new Dimension(500, 500); + treeMap = new TreeMapComponent(tree, dim); + + boolean catched = false; + try { + toolbar = new TreeMapToolbar(null); + } catch(NullPointerException e) { + catched = true; + } + assertTrue(catched); + try { + toolbar = new TreeMapToolbar(treeMap); + } catch (NullPointerException e) { + Assert.fail("Should not throw any exception."); + } + } + }); + } + + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapZoomBarTest.java Thu Aug 20 14:12:33 2015 +0200 @@ -0,0 +1,94 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.heap.analysis.client.swing.internal; + +import static org.junit.Assert.assertTrue; + +import java.awt.Dimension; +import java.lang.reflect.InvocationTargetException; + +import javax.swing.SwingUtilities; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import com.redhat.thermostat.annotations.internal.CacioTest; + +@Category(CacioTest.class) +public class TreeMapZoomBarTest { + + private TreeMapComponent treeMap; + @SuppressWarnings("unused") + private TreeMapZoomBar zoomBar; + + private static TreeMapNode tree; + private static Dimension dim; + + @Before + public void setUp() { + tree = new TreeMapNode(1); + dim = new Dimension(500, 500); + } + + @Test + public final void testTreeMapZoomBar() throws InvocationTargetException, InterruptedException { + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + boolean catched = false; + try { + zoomBar = new TreeMapZoomBar(null); + } catch(NullPointerException e) { + catched = true; + } + assertTrue(catched); + try { + treeMap = new TreeMapComponent(tree, dim); + zoomBar = new TreeMapZoomBar(treeMap); + } catch (NullPointerException e) { + Assert.fail("Should not throw any exception."); + } + } + }); + } + + +}