changeset 1131:9917555955a0

Heap Dumper refactoring reviewed-by: vanaltj review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-June/006924.html
author Mario Torre <neugens.limasoftware@gmail.com>
date Wed, 05 Jun 2013 20:26:44 +0200
parents bb4bde056ead
children 50b5ae6a4a81
files client/core/src/main/java/com/redhat/thermostat/client/ui/Palette.java client/swing/src/main/java/com/redhat/thermostat/client/swing/components/GaussianBlur.java client/swing/src/main/java/com/redhat/thermostat/client/swing/components/OverlayPanel.java client/swing/src/main/java/com/redhat/thermostat/client/swing/components/ShadowLabel.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumpListView.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumpListViewProvider.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapIconResources.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapView.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/Activator.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpController.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpListController.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumperServiceImpl.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/locale/LocaleResources.java vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/core/list_dumps.png vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/core/pin_mask.png vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/locale/strings.properties vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ActivatorTest.java vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpControllerTest.java vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpListControllerTest.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/Activator.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingView.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SwingHeapDumpListView.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SwingHeapDumpListViewProvider.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/stats/HeapChartPanel.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/stats/OverlayComponent.java vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ActivatorTest.java vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapDumpListViewTest.java vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingViewTest.java
diffstat 28 files changed, 1276 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/Palette.java	Mon Jun 03 11:03:06 2013 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/Palette.java	Wed Jun 05 20:26:44 2013 +0200
@@ -74,6 +74,10 @@
     BLACK(Color.BLACK),
     WHITE(Color.WHITE),
 
+    DARK_BLUE(new Color(0x030A0C)),
+    ROYAL_BLUE(new Color(0x0A242D)),
+    ELEGANT_CYAN(new Color(0x39CAFF)),
+    
     /* END */ ;
     
     private Color color;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/GaussianBlur.java	Wed Jun 05 20:26:44 2013 +0200
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2012, 2013 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.client.swing.components;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ConvolveOp;
+import java.awt.image.Kernel;
+
+/**
+ * Apply Gaussian Blur on images.
+ * 
+ * <br /><br />
+ *
+ * The formula for Gaussian blur is:
+ *
+ * <pre>
+ * 
+ * G(x, y) = ({@link Math#E} ^ (-(x^2 + y^2) / (2 * SIGMA^2))) / sqrt(2 * {@link Math#PI} * SIGMA^2))
+ * 
+ * </pre>
+ *
+ * Where {@code SIGMA} is the standard deviation, {@code x} and {@code y}
+ * represent the distance from the horizontal and vertical axis respectively.
+ * 
+ * In this implementation {@code SIGMA} is always 1/3 of the radius of the
+ * applied filter.
+ * 
+ * <br /><br />
+ *
+ * Since the Gaussian filter is separable, meaning that can be applied to a
+ * two-dimensional image as two independent one-dimensional calculations,
+ * so this filter will first create a {@link Kernel} for the horizontal
+ * direction and then a second {@link Kernel} for the vertical one.
+ */
+public class GaussianBlur {
+        
+    static ConvolveOp[] createFilters(int radius) {
+        ConvolveOp[] filters = new ConvolveOp[2];
+        
+        double sigma = radius / 3.0;
+        double sigmaSquareDivisor = 2.0 * Math.pow(sigma, 2);
+        
+        double sqrtDivisor = Math.sqrt(sigmaSquareDivisor * Math.PI);
+        
+        float total = 0f;
+        float [] matrix = new float[radius * 2];
+        for (int i = -radius; i < radius; i++) {
+            
+            double distance = -(i * i);
+            double midpoint = Math.exp(distance / sigmaSquareDivisor) / sqrtDivisor;
+            
+            matrix[i + radius] = (float) midpoint;
+            
+            // keep this to normalise the matrix to avoid a darkening or
+            // brightening of the image
+            total += (float) midpoint;
+        }
+        
+        // normalise the matrix now
+        for (int i = 0; i < matrix.length; i++) {
+            matrix[i] /= total;
+        }
+        
+        Kernel horizontalKernel = new Kernel(matrix.length, 1, matrix);
+        Kernel verticalKernel = new Kernel(1, matrix.length, matrix);
+        
+        filters[0] = new ConvolveOp(horizontalKernel, ConvolveOp.EDGE_NO_OP, null);  
+        filters[1] = new ConvolveOp(verticalKernel, ConvolveOp.EDGE_NO_OP, null);  
+
+        return filters;
+    }
+
+    public static BufferedImage applyFilter(int radius, BufferedImage src) {
+        ConvolveOp[] filters = GaussianBlur.createFilters(radius);
+               
+        src = filters[0].filter(src, null);
+        src = filters[1].filter(src, null);
+
+        return src;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/OverlayPanel.java	Wed Jun 05 20:26:44 2013 +0200
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2012, 2013 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.client.swing.components;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.event.KeyAdapter;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseMotionAdapter;
+import java.awt.geom.Area;
+import java.awt.geom.GeneralPath;
+import java.awt.image.BufferedImage;
+
+import javax.swing.JPanel;
+
+import com.redhat.thermostat.client.swing.GraphicsUtils;
+import com.redhat.thermostat.client.ui.Palette;
+
+/**
+ * A panel meant to be stacked on top of existing components to display
+ * informations in an floating overlay.
+ * 
+ * <br /><br />
+ * 
+ * <strong>Note</strong>: By default, the panel is invisible even when the
+ * component it belongs sets all its children to be visible.
+ * For this reason, the {@link #setVisible(boolean)}
+ * method is a no-op when setting the panel visible and the user should
+ * only use {@link #setOverlayVisible(boolean)} to turn on and off the
+ * visibility of this panel.
+ */
+@SuppressWarnings("serial")
+public class OverlayPanel extends JPanel {
+    
+    private JPanel content;
+    private JPanel titlePane;
+
+    private ShadowLabel overlayTitle;
+    
+    private boolean displayArrow;
+    
+    /**
+     * Creates a new {@link OverlayPanel}, with an arrow facing upward.
+     */
+    public OverlayPanel(String title) {
+        this(title, true);
+    }
+    
+    /**
+     * Creates a new {@link OverlayPanel}. The panel will display an up facing
+     * arrow if {@code displayArrow} is {@code true}.
+     */
+    public OverlayPanel(String title, boolean displayArrow) {
+        
+        this.displayArrow = displayArrow;
+        
+        setOpaque(false);
+        setBorder(new OverlayBorder());
+        setLayout(new BorderLayout(0, 10));
+        
+        titlePane = new JPanel();
+        titlePane.setOpaque(true);
+
+        overlayTitle = new ShadowLabel(title);
+        
+        titlePane.setBorder(new TitleBorder());
+        titlePane.setBackground(Palette.ROYAL_BLUE.getColor());
+        overlayTitle.setForeground(Palette.WHITE.getColor());
+
+        titlePane.add(overlayTitle);
+        
+        content = new JPanel();
+        content.setOpaque(false);
+        
+        super.add(titlePane, BorderLayout.NORTH);
+        super.add(content, BorderLayout.CENTER);
+
+        // a bit more useful layout than the default
+        content.setLayout(new BorderLayout());
+        
+        setOverlayVisible(false);
+        
+        // filter events, we don't want them to reach components below us
+        addMouseListener(new MouseAdapter() {});
+        addMouseMotionListener(new MouseMotionAdapter() {});
+        addKeyListener(new KeyAdapter() {});
+        setFocusTraversalKeysEnabled(false);
+    }
+    
+    @Override
+    public Component add(Component comp) {
+        return content.add(comp);
+    }
+    
+    @Override
+    public void remove(Component comp) {
+        content.remove(comp);
+    }
+
+    @Override
+    public void removeAll() {
+        content.removeAll();
+    }
+    
+    @Override
+    protected void paintComponent(Graphics g) {
+
+        GraphicsUtils utils = GraphicsUtils.getInstance();
+
+        Graphics2D graphics = utils.createAAGraphics(g);
+        graphics.setColor(utils.deriveWithAlpha(Palette.PALE_GRAY.getColor(), 200));
+ 
+        Rectangle clip = graphics.getClipBounds();
+        Insets borderInsets = getBorder().getBorderInsets(this);
+        
+        clip.height = clip.height - borderInsets.bottom - borderInsets.top;
+        clip.width = clip.width - borderInsets.left - borderInsets.right;
+        
+        graphics.translate(borderInsets.left, borderInsets.top);
+        graphics.fillRect(clip.x, clip.y, clip.width, clip.height);
+        
+        graphics.dispose();
+    }
+    
+    /**
+     * No-op when setting the panel visible.
+     * Please, use {@link #setOverlayVisible(boolean)} instead.
+     * 
+     * @see #setOverlayVisible(boolean)
+     */
+    @Override
+    public void setVisible(boolean visible) {
+        // no-op otherwise
+        if (!visible) {
+            setOverlayVisible(visible);
+        }
+    }
+    
+    /**
+     * Sets the visibility of this panel.
+     */
+    public void setOverlayVisible(boolean visible) {
+        super.setVisible(visible);
+    }
+    
+    /**
+     * Paints the border of the TitlePane
+     */
+    private class TitleBorder extends DebugBorder {
+        
+        @Override
+        public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
+            g.setColor(overlayTitle.getForeground());
+            g.drawLine(x, y + height - 1, x + width - 1, y + height - 1);
+        }
+        
+        @Override
+        public Insets getBorderInsets(Component c, Insets insets) {
+            
+            insets.top = 2;
+            insets.left = 2;
+            insets.right = 2;
+            insets.bottom = 2;
+            
+            return insets;
+        }
+    }
+    
+    /**
+     * Paints the drop shadow around the overlay.
+     */
+    private class OverlayBorder extends DebugBorder {
+        
+        private BufferedImage buffer; 
+        
+        private static final boolean DEBUG = false;
+                
+        @Override
+        public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
+            if (DEBUG) {
+                super.paintBorder(c, g, x, y, width, height);
+                return;
+            }
+            
+            if (buffer != null && buffer.getWidth() == getWidth() && buffer.getHeight() == getHeight()) {
+                g.drawImage(buffer, 0, 0, null);
+                return;
+            }
+                        
+            GraphicsUtils utils = GraphicsUtils.getInstance();
+
+            buffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
+            Graphics bufferGraphics = buffer.getGraphics();
+            Graphics2D graphics = utils.createAAGraphics(bufferGraphics);
+            bufferGraphics.dispose();
+            
+            Insets insets = getBorderInsets(c);
+                                    
+            Area clip = new Area(new Rectangle(x, y, width, height));
+            BufferedImage dropShadow = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+
+            x = x + insets.left;
+            y = y + insets.top;
+            
+            width = width - insets.right - insets.left;
+            height = height - insets.top - insets.bottom;
+            
+            Area inside = new Area(new Rectangle(x, y, width, height));
+            clip.subtract(inside);
+            graphics.setClip(clip);
+            
+            Graphics2D dropShadowGraphics = dropShadow.createGraphics();
+            dropShadowGraphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+            dropShadowGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+
+            dropShadowGraphics.setColor(utils.deriveWithAlpha(Palette.BLACK.getColor(), 100));
+            dropShadowGraphics.fillRoundRect(x - 5, y + 5, width + 10, height + 5, 15, 15);
+            dropShadowGraphics.dispose();
+            
+            dropShadow = GaussianBlur.applyFilter(20, dropShadow);
+            
+            graphics.drawImage(dropShadow, 0, 0, null);
+            
+            if (displayArrow) {
+                int x1Points[] = {0, 4, 4, 8};
+                int y1Points[] = {4, 0, 0, 4};
+
+                GeneralPath polyline =  new GeneralPath(GeneralPath.WIND_EVEN_ODD, x1Points.length);
+            
+                polyline.moveTo(x1Points[0], y1Points[0]);
+                for (int index = 1; index < x1Points.length; index++) {
+                    polyline.lineTo(x1Points[index], y1Points[index]);
+                };
+                polyline.closePath();
+            
+                graphics.setColor(Palette.BLACK.getColor());
+                x += (width / 2) - 4;
+                y -= 4;
+                graphics.translate(x, y);
+                graphics.fill(polyline);
+            }
+            
+            graphics.dispose();
+            
+            g.drawImage(buffer, 0, 0, null);
+        }
+        
+        @Override
+        public Insets getBorderInsets(Component c, Insets insets) {
+            
+            insets.top = 30;
+            insets.left = 50;
+            insets.right = 50;
+            insets.bottom = 50;
+            
+            return insets;
+        }
+    }
+}
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/ShadowLabel.java	Mon Jun 03 11:03:06 2013 +0200
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/ShadowLabel.java	Wed Jun 05 20:26:44 2013 +0200
@@ -67,7 +67,7 @@
         protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, int textY) {
             GraphicsUtils graphicsUtils = GraphicsUtils.getInstance();
             Graphics2D graphics = graphicsUtils.createAAGraphics(g);
-            graphicsUtils.drawStringWithShadow(l, graphics, s, getForeground(), textX, textY);
+            graphicsUtils.drawStringWithShadow(l, graphics, s, ShadowLabel.this.getForeground(), textX, textY);
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumpListView.java	Wed Jun 05 20:26:44 2013 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012, 2013 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.core;
+
+import java.util.List;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.core.views.UIComponent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionNotifier;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+
+/**
+ *
+ */
+public abstract class HeapDumpListView extends BasicView implements UIComponent {
+    public enum ListAction {
+        DUMP_SELECTED,
+    }
+    
+    protected final ActionNotifier<ListAction> listNotifier;
+    protected HeapDumpListView() {
+        listNotifier = new ActionNotifier<ListAction>(this);
+    }
+    
+    public void addListListener(ActionListener<ListAction> listener) {
+        listNotifier.addActionListener(listener);
+    }
+    
+    public void removeListListener(ActionListener<ListAction> listener) {
+        listNotifier.removeActionListener(listener);
+    }
+
+    public abstract void setDumps(List<HeapDump> dumps);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumpListViewProvider.java	Wed Jun 05 20:26:44 2013 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012, 2013 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.core;
+
+import com.redhat.thermostat.annotations.ExtensionPoint;
+import com.redhat.thermostat.client.core.views.ViewProvider;
+
+@ExtensionPoint
+public interface HeapDumpListViewProvider extends ViewProvider {
+
+    @Override
+    public HeapDumpListView createView();
+}
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapIconResources.java	Mon Jun 03 11:03:06 2013 +0200
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapIconResources.java	Wed Jun 05 20:26:44 2013 +0200
@@ -47,6 +47,7 @@
 public class HeapIconResources {
 
     public static final String PIN_MASK = "com/redhat/thermostat/vm/heap/analysis/client/core/pin_mask.png";
+    public static final String LIST_DUMPS = "com/redhat/thermostat/vm/heap/analysis/client/core/list_dumps.png";
 
     private static Map<String, IconDescriptor> icons = new HashMap<>();
     
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapView.java	Mon Jun 03 11:03:06 2013 +0200
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapView.java	Wed Jun 05 20:26:44 2013 +0200
@@ -52,6 +52,7 @@
         DUMP_REQUESTED,
         ANALYSE,
         REQUEST_ABORTED,
+        REQUEST_DISPLAY_DUMP_LIST,
     }
 
     public enum DumpDisabledReason {
@@ -90,5 +91,6 @@
 
     public abstract void displayWarning(LocalizedString string);
 
+    public abstract void openDumpListView(HeapDumpListView childView);
 }
 
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/Activator.java	Mon Jun 03 11:03:06 2013 +0200
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/Activator.java	Wed Jun 05 20:26:44 2013 +0200
@@ -53,6 +53,7 @@
 import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumperService;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider;
@@ -77,7 +78,8 @@
             HeapDumpDetailsViewProvider.class,
             HeapHistogramViewProvider.class,
             ObjectDetailsViewProvider.class,
-            ObjectRootsViewProvider.class
+            ObjectRootsViewProvider.class,
+            HeapDumpListViewProvider.class,
         };
 
         tracker = new MultipleServiceTracker(context, deps, new Action() {
@@ -106,10 +108,14 @@
                         .get(ObjectRootsViewProvider.class.getName());
                 Objects.requireNonNull(objectRootsViewProvider);
 
+                HeapDumpListViewProvider heapDumpListViewProvider = (HeapDumpListViewProvider) services
+                        .get(HeapDumpListViewProvider.class.getName());
+                
                 HeapDumperService service = new HeapDumperServiceImpl(appSvc,
                         vmInfoDao, vmMemoryStatDao, heapDao, viewProvider,
                         detailsViewProvider, histogramViewProvider,
-                        objectDetailsViewProvider, objectRootsViewProvider);
+                        objectDetailsViewProvider, objectRootsViewProvider,
+                        heapDumpListViewProvider);
                 Dictionary<String, String> properties = new Hashtable<>();
                 properties.put(Constants.GENERIC_SERVICE_CLASSNAME, VmRef.class.getName());
                 properties.put(InformationService.KEY_SERVICE_ID, HeapDumperService.SERVICE_ID);
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpController.java	Mon Jun 03 11:03:06 2013 +0200
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpController.java	Wed Jun 05 20:26:44 2013 +0200
@@ -57,6 +57,7 @@
 import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView.DumpDisabledReason;
@@ -92,7 +93,7 @@
     private HeapHistogramViewProvider histogramViewProvider;
     private ObjectDetailsViewProvider objectDetailsViewProvider;
     private ObjectRootsViewProvider objectRootsViewProvider;
-
+    private HeapDumpListViewProvider heapDumpListViewProvider;
 
     public HeapDumpController(final VmMemoryStatDAO vmMemoryStatDao,
                               final VmInfoDAO vmInfoDao,
@@ -101,11 +102,12 @@
                               HeapDumpDetailsViewProvider detailsViewProvider,
                               HeapHistogramViewProvider histogramProvider,
                               ObjectDetailsViewProvider objectDetailsProvider,
-                              ObjectRootsViewProvider objectRootsProvider)
+                              ObjectRootsViewProvider objectRootsProvider,
+                              HeapDumpListViewProvider heapDumpListViewProvider)
     {
         this(vmMemoryStatDao, vmInfoDao, heapDao, ref, appService, viewProvider,
              detailsViewProvider, histogramProvider, objectDetailsProvider,
-             objectRootsProvider, new HeapDumper(ref));
+             objectRootsProvider, heapDumpListViewProvider, new HeapDumper(ref));
     }
 
     HeapDumpController(final VmMemoryStatDAO vmMemoryStatDao,
@@ -117,6 +119,7 @@
                        HeapHistogramViewProvider histogramProvider,
                        ObjectDetailsViewProvider objectDetailsProvider,
                        ObjectRootsViewProvider objectRootsProvider,
+                       HeapDumpListViewProvider heapDumpListViewProvider,
                        final HeapDumper heapDumper)
     {
         this.objectDetailsViewProvider = objectDetailsProvider;
@@ -127,6 +130,7 @@
         this.ref = ref;
         this.vmDao = vmMemoryStatDao;
         this.heapDAO = heapDao;
+        this.heapDumpListViewProvider = heapDumpListViewProvider;
         
         model = new OverviewChart(
                     null,
@@ -188,6 +192,11 @@
                     view.disableHeapDumping(DumpDisabledReason.DUMP_IN_PROGRESS);
                     requestDump(heapDumper);
                     break;
+                    
+                case REQUEST_DISPLAY_DUMP_LIST:
+                    openDumpList();
+                    break;
+                    
                 case ANALYSE:
                     dump = (HeapDump) actionEvent.getPayload();
                     analyseDump(dump);
@@ -204,6 +213,21 @@
         }
     }
 
+    private void openDumpList() {
+        
+        appService.getApplicationExecutor().execute(new Runnable() {
+            @Override
+            public void run() {
+                List<HeapDump> dumps = getHeapDumps();
+                HeapDumpListController controller =
+                        new HeapDumpListController(heapDumpListViewProvider,
+                                                   HeapDumpController.this);
+                controller.setDumps(dumps);
+                view.openDumpListView(controller.getView());                
+            }
+        });
+    }
+    
     private void requestDump(final HeapDumper heapDumper) {
         appService.getApplicationExecutor().execute(new Runnable() {
             
@@ -220,9 +244,8 @@
         });
     }
 
-    private void analyseDump(final HeapDump dump) {
+    void analyseDump(final HeapDump dump) {
         appService.getApplicationExecutor().execute(new Runnable() {
-            
             @Override
             public void run() {
                 showHeapDumpDetails(dump);
@@ -253,6 +276,15 @@
         return translator.localize(LocaleResources.HEAP_SECTION_TITLE);
     }
 
+    private List<HeapDump> getHeapDumps() {
+        Collection<HeapInfo> heapInfos = heapDAO.getAllHeapInfo(ref);
+        List<HeapDump> heapDumps = new ArrayList<HeapDump>(heapInfos.size());
+        for (HeapInfo heapInfo : heapInfos) {
+            heapDumps.add(new HeapDump(heapInfo, heapDAO));
+        }
+        return heapDumps;
+    }
+    
     class HeapOverviewDataCollector implements Runnable {
 
         private long desiredUpdateTimeStamp = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1);
@@ -264,12 +296,7 @@
         }
 
         private void checkForHeapDumps() {
-            Collection<HeapInfo> heapInfos = heapDAO.getAllHeapInfo(ref);
-            List<HeapDump> heapDumps = new ArrayList<HeapDump>(heapInfos.size());
-            for (HeapInfo heapInfo : heapInfos) {
-                heapDumps.add(new HeapDump(heapInfo, heapDAO));
-            }
-            view.updateHeapDumpList(heapDumps);
+            view.updateHeapDumpList(getHeapDumps());
         }
 
         private void updateMemoryChartAndDisplay() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpListController.java	Wed Jun 05 20:26:44 2013 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012, 2013 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.core.internal;
+
+import java.util.List;
+
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListView.ListAction;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+
+public class HeapDumpListController {
+
+    private HeapDumpListView view;
+    
+    public HeapDumpListController(HeapDumpListViewProvider viewProvider, final HeapDumpController mainController) {
+        view = viewProvider.createView();
+        view.addListListener(new ActionListener<HeapDumpListView.ListAction>() {
+            @Override
+            public void actionPerformed(ActionEvent<ListAction> actionEvent) {
+                mainController.analyseDump((HeapDump) actionEvent.getPayload());
+            }
+        });
+    }
+    
+    public HeapDumpListView getView() {
+        return view;
+    }
+
+    public void setDumps(List<HeapDump> dumps) {
+        view.setDumps(dumps);
+    }
+}
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumperServiceImpl.java	Mon Jun 03 11:03:06 2013 +0200
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumperServiceImpl.java	Wed Jun 05 20:26:44 2013 +0200
@@ -43,6 +43,7 @@
 import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumperService;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider;
@@ -67,13 +68,16 @@
     private ObjectDetailsViewProvider objectDetailsViewProvider;
     private ObjectRootsViewProvider objectRootsViewProvider;
 
+    private HeapDumpListViewProvider heapDumpListViewProvider;
+    
     public HeapDumperServiceImpl(ApplicationService appService,
             VmInfoDAO vmInfoDao, VmMemoryStatDAO vmMemoryStatDao,
             HeapDAO heapDao, HeapViewProvider viewProvider,
             HeapDumpDetailsViewProvider detailsViewProvider,
             HeapHistogramViewProvider histogramViewProvider,
             ObjectDetailsViewProvider objectDetailsViewProvider,
-            ObjectRootsViewProvider objectRootsViewProvider) {
+            ObjectRootsViewProvider objectRootsViewProvider,
+            HeapDumpListViewProvider heapDumpListViewProvider) {
         this.vmInfoDao = vmInfoDao;
         this.vmMemoryStatDao = vmMemoryStatDao;
         this.heapDao = heapDao;
@@ -83,12 +87,14 @@
         this.histogramViewProvider = histogramViewProvider;
         this.objectDetailsViewProvider = objectDetailsViewProvider;
         this.objectRootsViewProvider = objectRootsViewProvider;
+        this.heapDumpListViewProvider = heapDumpListViewProvider;
     }
 
     @Override
     public InformationServiceController<VmRef> getInformationServiceController(VmRef ref) {
         return new HeapDumpController(vmMemoryStatDao, vmInfoDao, heapDao, ref, appService,
-                viewProvider, detailsViewProvider, histogramViewProvider, objectDetailsViewProvider, objectRootsViewProvider);
+                viewProvider, detailsViewProvider, histogramViewProvider, objectDetailsViewProvider,
+                objectRootsViewProvider, heapDumpListViewProvider);
     }
 
     @Override
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/locale/LocaleResources.java	Mon Jun 03 11:03:06 2013 +0200
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/locale/LocaleResources.java	Wed Jun 05 20:26:44 2013 +0200
@@ -71,6 +71,10 @@
     TRIGGER_HEAP_DUMP,
     HEAP_DUMP_IN_PROGRESS,
     PROCESS_EXITED,
+    
+    DUMPS_LIST,
+    LIST_DUMPS_ACTION,
+    
     ;
 
     static final String RESOURCE_BUNDLE = "com.redhat.thermostat.vm.heap.analysis.client.locale.strings";
Binary file vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/core/list_dumps.png has changed
Binary file vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/core/pin_mask.png has changed
--- a/vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/locale/strings.properties	Mon Jun 03 11:03:06 2013 +0200
+++ b/vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/locale/strings.properties	Wed Jun 05 20:26:44 2013 +0200
@@ -28,5 +28,7 @@
 OBJECT_ROOTS_VIEW_TITLE = Object Roots
 
 TRIGGER_HEAP_DUMP = Heap Dump
+LIST_DUMPS_ACTION = List Dumps
+DUMPS_LIST = Available Dumps
 HEAP_DUMP_IN_PROGRESS = dumping...
 PROCESS_EXITED = Process exited.
--- a/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ActivatorTest.java	Mon Jun 03 11:03:06 2013 +0200
+++ b/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ActivatorTest.java	Wed Jun 05 20:26:44 2013 +0200
@@ -48,6 +48,7 @@
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.testutils.StubBundleContext;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
@@ -86,6 +87,7 @@
         HeapHistogramViewProvider histogramViewProvider = mock(HeapHistogramViewProvider.class);
         ObjectDetailsViewProvider objectDetailsViewProvider = mock(ObjectDetailsViewProvider.class);
         ObjectRootsViewProvider objectRootsViewProvider = mock(ObjectRootsViewProvider.class);
+        HeapDumpListViewProvider heapDumpListViewProvider = mock(HeapDumpListViewProvider.class);
 
         context.registerService(VmInfoDAO.class, vmInfoDao, null);
         context.registerService(VmMemoryStatDAO.class, vmMemoryStatDAO, null);
@@ -97,6 +99,7 @@
         context.registerService(HeapHistogramViewProvider.class, histogramViewProvider, null);
         context.registerService(ObjectDetailsViewProvider.class, objectDetailsViewProvider, null);
         context.registerService(ObjectRootsViewProvider.class, objectRootsViewProvider, null);
+        context.registerService(HeapDumpListViewProvider.class, heapDumpListViewProvider, null);
 
         Activator activator = new Activator();
 
@@ -107,7 +110,7 @@
         activator.stop(context);
 
         assertEquals(0, context.getServiceListeners().size());
-        assertEquals(9, context.getAllServices().size());
+        assertEquals(10, context.getAllServices().size());
     }
 
 }
--- a/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpControllerTest.java	Mon Jun 03 11:03:06 2013 +0200
+++ b/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpControllerTest.java	Wed Jun 05 20:26:44 2013 +0200
@@ -77,6 +77,7 @@
 import com.redhat.thermostat.storage.model.VmInfo;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsView;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramView;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView;
@@ -121,6 +122,8 @@
     private ObjectDetailsViewProvider objectDetailsProvider;
     private ObjectRootsViewProvider objectRootsProvider;
 
+    private HeapDumpListViewProvider heapDumpListViewProvider;
+    
     @Before
     public void setUp() {
         heapDao = mock(HeapDAO.class);
@@ -132,6 +135,8 @@
         appService = mock(ApplicationService.class);
         heapDumper = mock(HeapDumper.class);
 
+        heapDumpListViewProvider = mock(HeapDumpListViewProvider.class);
+        
         setUpView();
     }
 
@@ -195,7 +200,8 @@
 
         controller = new HeapDumpController(vmDao, vmInfoDao, heapDao, ref, appService,
                 viewProvider, detailsViewProvider, histogramProvider,
-                objectDetailsProvider, objectRootsProvider, heapDumper);
+                objectDetailsProvider, objectRootsProvider, heapDumpListViewProvider,
+                heapDumper);
     }
     
     @After
@@ -279,7 +285,8 @@
         VmRef ref = mock(VmRef.class);
         controller = new HeapDumpController(vmDao, vmInfoDao, heapDao, ref, appService,
                 viewProvider, detailsViewProvider, histogramProvider,
-                objectDetailsProvider, objectRootsProvider, heapDumper);
+                objectDetailsProvider, objectRootsProvider, heapDumpListViewProvider,
+                heapDumper);
         
         verify(view, times(1)).setChildView(any(HeapView.class));
         verify(view, times(1)).openDumpView();
@@ -304,7 +311,8 @@
         VmRef ref = mock(VmRef.class);
         controller = new HeapDumpController(vmDao, vmInfoDao, heapDao, ref, appService,
                 viewProvider, detailsViewProvider, histogramProvider,
-                objectDetailsProvider, objectRootsProvider, heapDumper);
+                objectDetailsProvider, objectRootsProvider, heapDumpListViewProvider,
+                heapDumper);
         
         verify(view, times(0)).openDumpView();
     }
@@ -324,7 +332,8 @@
 
         controller = new HeapDumpController(vmDao, vmInfoDao, heapDao, ref, appService,
                 viewProvider, detailsViewProvider, histogramProvider,
-                objectDetailsProvider, objectRootsProvider, heapDumper);
+                objectDetailsProvider, objectRootsProvider, heapDumpListViewProvider,
+                heapDumper);
 
         verify(view).disableHeapDumping(DumpDisabledReason.PROCESS_DEAD);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpListControllerTest.java	Wed Jun 05 20:26:44 2013 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2012, 2013 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.core.internal;
+
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListView.ListAction;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.junit.Assert.assertNotNull;
+
+public class HeapDumpListControllerTest {
+
+    private HeapDumpController mainController;
+    private HeapDumpListViewProvider provider;
+    private HeapDumpListView view;
+    
+    @Before
+    public void setUp() throws Exception {
+        provider = mock(HeapDumpListViewProvider.class);
+        view = mock(HeapDumpListView.class);
+        when(provider.createView()).thenReturn(view);
+        
+        mainController = mock(HeapDumpController.class);
+    }
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Test
+    public void testAnalyseDump() {        
+        
+        HeapDump dump = mock(HeapDump.class);
+        
+        ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addListListener(viewArgumentCaptor.capture());
+        
+        HeapDumpListController controller = new HeapDumpListController(provider, mainController);
+        
+        ActionListener<ListAction> listener = viewArgumentCaptor.getValue();
+        assertNotNull(listener);
+        
+        ActionEvent<ListAction> actionEvent = new ActionEvent<HeapDumpListView.ListAction>(view, ListAction.DUMP_SELECTED);
+        actionEvent.setPayload(dump);
+        listener.actionPerformed(actionEvent);
+        
+        verify(mainController).analyseDump(dump);
+        verifyNoMoreInteractions(mainController);
+    }
+    
+    @Test
+    public void testSetDumps() {        
+        
+        List<HeapDump> dumps = mock(List.class);
+        
+        HeapDumpListController controller = new HeapDumpListController(provider, mainController);
+        
+        controller.setDumps(dumps);
+        
+        verify(view).setDumps(dumps);
+    }
+}
--- a/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/Activator.java	Mon Jun 03 11:03:06 2013 +0200
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/Activator.java	Wed Jun 05 20:26:44 2013 +0200
@@ -40,6 +40,7 @@
 import org.osgi.framework.BundleContext;
 
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
@@ -60,6 +61,8 @@
         context.registerService(ObjectDetailsViewProvider.class.getName(), objectDetailsViewProvider, null);
         ObjectRootsViewProvider objectRootsViewProvider = new SwingObjectRootsViewProvider();
         context.registerService(ObjectRootsViewProvider.class.getName(), objectRootsViewProvider, null);
+        HeapDumpListViewProvider heapListViewProvider = new SwingHeapDumpListViewProvider();
+        context.registerService(HeapDumpListViewProvider.class.getName(), heapListViewProvider, null);
     }
 
     @Override
--- a/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingView.java	Mon Jun 03 11:03:06 2013 +0200
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingView.java	Wed Jun 05 20:26:44 2013 +0200
@@ -45,26 +45,27 @@
 import javax.swing.BoxLayout;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
+import javax.swing.OverlayLayout;
 import javax.swing.SwingUtilities;
 
-import com.redhat.thermostat.shared.locale.LocalizedString;
-import com.redhat.thermostat.shared.locale.Translate;
-import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.stats.HeapDumpListener;
-import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.stats.HeapSelectionEvent;
-
-import org.jfree.chart.axis.DateAxis;
-import org.jfree.chart.event.AxisChangeEvent;
-import org.jfree.chart.event.AxisChangeListener;
-import org.jfree.chart.plot.XYPlot;
-
 import com.redhat.thermostat.client.core.views.BasicView;
 import com.redhat.thermostat.client.swing.ComponentVisibleListener;
 import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.ActionToggleButton;
 import com.redhat.thermostat.client.swing.components.HeaderPanel;
+import com.redhat.thermostat.client.swing.components.Icon;
+import com.redhat.thermostat.client.swing.components.OverlayPanel;
+import com.redhat.thermostat.shared.locale.LocalizedString;
+import com.redhat.thermostat.shared.locale.Translate;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListView.ListAction;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapIconResources;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView;
 import com.redhat.thermostat.vm.heap.analysis.client.core.chart.OverviewChart;
 import com.redhat.thermostat.vm.heap.analysis.client.locale.LocaleResources;
 import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.stats.HeapChartPanel;
+import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.stats.HeapDumpListener;
+import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.stats.HeapSelectionEvent;
 import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.stats.StatsPanel;
 import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
 
@@ -78,6 +79,11 @@
     private HeaderPanel overview;
     
     private JPanel visiblePane;
+    private OverlayPanel overlay;
+    
+    private ActionToggleButton showHeapListButton;
+    
+    private JPanel stack;
     
     public HeapSwingView() {
         stats = new StatsPanel();
@@ -102,9 +108,39 @@
         heapDetailPanel = new HeapPanel();
         
         overview = new HeaderPanel(translator.localize(LocaleResources.HEAP_OVERVIEW_TITLE).getContents());
-        overview.setContent(stats);
+
+        stack = new JPanel();
+        stack.setLayout(new OverlayLayout(stack));
+        
+        overlay = new OverlayPanel(translator.localize(LocaleResources.DUMPS_LIST).getContents());
+        stack.add(overlay);
+        stack.add(stats);
+        stats.setOpaque(false);
+        
+        overlay.setAlignmentX(-1.f);
+        overlay.setAlignmentY(1.f);
+
+        overview.setContent(stack);
         overview.addHierarchyListener(new ViewVisibleListener());
 
+        Icon listDumpIcon = new Icon(HeapIconResources.getIcon(HeapIconResources.LIST_DUMPS));
+        
+        showHeapListButton = new ActionToggleButton(listDumpIcon, translator.localize(LocaleResources.LIST_DUMPS_ACTION).getContents());
+        showHeapListButton.setToolTipText(translator.localize(LocaleResources.LIST_DUMPS_ACTION).getContents());
+        showHeapListButton.setName("LIST_DUMPS_ACTION");
+
+        showHeapListButton.getToolbarButton().addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                if (overlay.isVisible()) {
+                    overlay.setOverlayVisible(false);
+                } else {
+                    heapDumperNotifier.fireAction(HeapDumperAction.REQUEST_DISPLAY_DUMP_LIST);
+                }
+            }
+        });
+        overview.addToolBarButton(showHeapListButton);
+        
         // at the beginning, only the overview is visible
         visiblePane.add(overview);
     }
@@ -132,16 +168,6 @@
                 
                 final HeapChartPanel charts = new HeapChartPanel(model.getChart());
                 
-                XYPlot plot = model.getChart().getXYPlot();
-                DateAxis domainAxis = (DateAxis) plot.getDomainAxis();
-                domainAxis.addChangeListener(new AxisChangeListener() {
-                    @Override
-                    public void axisChanged(AxisChangeEvent event) {
-                        // somehow the chart panel doesn't see this
-                        charts.revalidate();
-                    }
-                });
-                
                 /*
                  * By default, ChartPanel scales itself instead of redrawing things when
                  * it's re-sized. To have it resize automatically, we need to set minimum
@@ -155,7 +181,9 @@
 
                 charts.setMaximumDrawHeight(Integer.MAX_VALUE);
                 charts.setMaximumDrawWidth(Integer.MAX_VALUE);
-
+                
+                charts.setOpaque(false);
+                
                 stats.setChartPanel(charts);
             }
         });
@@ -277,5 +305,43 @@
     public void displayWarning(LocalizedString string) {
         JOptionPane.showMessageDialog(visiblePane, string.getContents(), "Warning", JOptionPane.WARNING_MESSAGE);
     }
+    
+    private void closeDumpListView() {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                showHeapListButton.getToolbarButton().doClick();
+            }
+        });
+    }
+    
+    @Override
+    public void openDumpListView(HeapDumpListView view) {
+        if (view instanceof SwingHeapDumpListView) {
+            SwingHeapDumpListView swingView = (SwingHeapDumpListView) view;
+            view.addListListener(new com.redhat.thermostat.common.ActionListener<HeapDumpListView.ListAction>() {
+                @Override
+                public void actionPerformed(com.redhat.thermostat.common.ActionEvent<ListAction> actionEvent) {
+                    switch (actionEvent.getActionId()) {
+                    case DUMP_SELECTED:
+                        closeDumpListView();
+                        break;
+                        
+                    default:
+                        break;
+                    }
+                }
+            });
+            
+            final Component dumpListView = swingView.getUiComponent();
+            SwingUtilities.invokeLater(new Runnable() {
+                @Override
+                public void run() {
+                    overlay.removeAll();
+                    overlay.add(dumpListView);                    
+                    overlay.setOverlayVisible(true);
+                }
+            });
+        }
+    }
 }
-
--- /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/SwingHeapDumpListView.java	Wed Jun 05 20:26:44 2013 +0200
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2012, 2013 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.Component;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import javax.swing.DefaultListModel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.ListCellRenderer;
+import javax.swing.SwingUtilities;
+
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.ShadowLabel;
+import com.redhat.thermostat.client.ui.Palette;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListView;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+
+public class SwingHeapDumpListView extends HeapDumpListView implements SwingComponent {
+
+    private JPanel container;
+    private JScrollPane scrollPane;
+    private HeapDumpModel model;
+    private JList<HeapDump> list;
+
+    public SwingHeapDumpListView() {
+        container = new JPanel();
+        container.setName(getClass().getName());
+        container.setLayout(new BorderLayout(0, 0));
+        container.setOpaque(false);
+
+        model = new HeapDumpModel();
+        list = new JList<>(model);
+        list.setName(getClass().getName() + "_LIST");
+        list.setBorder(null);
+        list.setOpaque(false);
+        list.addMouseListener(new MouseAdapter() {
+            public void mouseClicked(MouseEvent evt) {
+                if (evt.getClickCount() == 2) {
+                    int index = list.locationToIndex(evt.getPoint());
+                    HeapDump dump = model.get(index);
+                    listNotifier.fireAction(ListAction.DUMP_SELECTED, dump);
+                }
+            }
+        });
+        
+        list.setCellRenderer(new HeapCellRenderer());
+        
+        scrollPane = new JScrollPane(list);
+        scrollPane.setBorder(null);
+        scrollPane.setViewportBorder(null);
+        
+        scrollPane.getViewport().setOpaque(false);
+        scrollPane.setOpaque(false);
+
+        container.add(scrollPane, BorderLayout.CENTER);
+    }
+    
+    @Override
+    public Component getUiComponent() {
+        return container;
+    }
+    
+    @Override
+    public void setDumps(List<HeapDump> dumps) {
+        
+        final List<HeapDump> _dumps = new ArrayList<>(dumps);
+        Collections.sort(_dumps, new DumpsComparator());
+        
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                model.clear();
+                for (HeapDump  dump : _dumps) {
+                    model.addElement(dump);
+                    container.repaint();
+                }
+            }
+        });
+    }
+    
+    @SuppressWarnings("serial")
+    private class HeapDumpModel extends DefaultListModel<HeapDump> {}
+    
+    private class DumpsComparator implements Comparator<HeapDump> {
+        @Override
+        public int compare(HeapDump o1, HeapDump o2) {
+            // TODO: descending order only for now, we should allow the users
+            // to sort this via the UI though
+            int result = Long.compare(o1.getTimestamp(), o2.getTimestamp());
+            return -result;
+        }
+    }
+    
+    private class HeapCellRenderer implements ListCellRenderer<HeapDump> {
+
+        @Override
+        public Component getListCellRendererComponent(JList<? extends HeapDump> list, HeapDump value, int index,
+                                                      boolean isSelected, boolean cellHasFocus) {
+            
+            ShadowLabel label = new ShadowLabel(value.toString());
+            label.setForeground(Palette.ROYAL_BLUE.getColor());
+
+            if (!isSelected) {
+                label.setOpaque(false);
+            } else {
+                label.setOpaque(true);
+                label.setBackground(Palette.ELEGANT_CYAN.getColor());
+            }
+            
+            return label;
+        }
+        
+    }
+}
--- /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/SwingHeapDumpListViewProvider.java	Wed Jun 05 20:26:44 2013 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2012, 2013 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 com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListViewProvider;
+
+public class SwingHeapDumpListViewProvider implements HeapDumpListViewProvider {
+    
+    @Override
+    public HeapDumpListView createView() {
+        return new SwingHeapDumpListView();
+    }
+}
--- a/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/stats/HeapChartPanel.java	Mon Jun 03 11:03:06 2013 +0200
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/stats/HeapChartPanel.java	Wed Jun 05 20:26:44 2013 +0200
@@ -51,8 +51,9 @@
     public HeapChartPanel(JFreeChart chart) {
    
         super(chart);
+        setName(HeapChartPanel.class.getName());
         
-        setName(HeapChartPanel.class.getName());
+        setupChart();
         
         setLayout(new HeapChartPanelLayout());
         chart.addChangeListener(new ChartChangeListener() {
@@ -63,6 +64,11 @@
         });
     }
 
+    private void setupChart() {
+        JFreeChart chart = getChart();
+        chart.setBackgroundPaint(getBackground());
+    }
+    
     @Override
     protected void paintChildren(Graphics g) {
         Rectangle2D area = getScreenDataArea();
--- a/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/stats/OverlayComponent.java	Mon Jun 03 11:03:06 2013 +0200
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/stats/OverlayComponent.java	Wed Jun 05 20:26:44 2013 +0200
@@ -93,12 +93,8 @@
 
             GraphicsUtils utils = GraphicsUtils.getInstance();
             Graphics2D graphics = utils.createAAGraphics(g);
-            
-            Color up = utils.deriveWithAlpha(Palette.DARK_GRAY.getColor(), 200);
-            Color bottom = utils.deriveWithAlpha(Palette.BLACK.getColor(), 200);
 
-            Paint gradient = new GradientPaint(0, 0, up, 0, getIconHeight(), bottom);
-            graphics.setPaint(gradient);
+            graphics.setColor(utils.deriveWithAlpha(OverlayComponent.this.getForeground(), 200));
             
             graphics.fillRect(x, y, getIconWidth(), getIconHeight());
             
@@ -120,6 +116,10 @@
         
         super("");
         
+        setOpaque(false);
+        
+        setForeground(Palette.ROYAL_BLUE.getColor());
+        
         setName(OverlayComponent.class.getName());
         
         Icon mask = new Icon(HeapIconResources.getIcon(HeapIconResources.PIN_MASK));
--- a/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ActivatorTest.java	Mon Jun 03 11:03:06 2013 +0200
+++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ActivatorTest.java	Wed Jun 05 20:26:44 2013 +0200
@@ -43,6 +43,7 @@
 
 import com.redhat.thermostat.testutils.StubBundleContext;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
@@ -66,7 +67,9 @@
         assertTrue(ctx.isServiceRegistered(HeapHistogramViewProvider.class.getName(), SwingHeapHistogramViewProvider.class));
         assertTrue(ctx.isServiceRegistered(ObjectDetailsViewProvider.class.getName(), SwingObjectDetailsViewProvider.class));
         assertTrue(ctx.isServiceRegistered(ObjectRootsViewProvider.class.getName(), SwingObjectRootsViewProvider.class));
-        assertEquals(5, ctx.getAllServices().size());
+        assertTrue(ctx.isServiceRegistered(HeapDumpListViewProvider.class.getName(), SwingHeapDumpListViewProvider.class));
+
+        assertEquals(6, ctx.getAllServices().size());
     }
 }
 
--- /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/HeapDumpListViewTest.java	Wed Jun 05 20:26:44 2013 +0200
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2012, 2013 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.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JFrame;
+
+import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
+
+import org.fest.swing.annotation.GUITest;
+import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
+import org.fest.swing.edt.GuiActionRunner;
+import org.fest.swing.edt.GuiTask;
+import org.fest.swing.fixture.FrameFixture;
+import org.fest.swing.fixture.JListFixture;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListView.ListAction;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+
+@RunWith(CacioFESTRunner.class)
+public class HeapDumpListViewTest {
+
+    private JFrame frame;
+    private FrameFixture frameFixture;
+    private SwingHeapDumpListView view;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+
+    @Before
+    public void setUp() {
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                view = new SwingHeapDumpListView();
+                frame = new JFrame();
+                frame.add(view.getUiComponent());
+
+            }
+        });
+        frameFixture = new FrameFixture(frame);
+    }
+
+    @After
+    public void tearDown() {
+        frameFixture.cleanUp();
+        frameFixture = null;
+    }
+    
+    @GUITest
+    @Test
+    public void testDumpSelectedFired() {
+        
+        final boolean [] result = new boolean[1];
+        final HeapDump [] selectedHeap = new HeapDump[1];
+
+        view.addListListener(new ActionListener<HeapDumpListView.ListAction>() {
+            @Override
+            public void actionPerformed(ActionEvent<ListAction> actionEvent) {
+                result[0] = true;
+                selectedHeap[0] = (HeapDump) actionEvent.getPayload();
+            }
+        });
+        
+        frameFixture.show();
+        
+        HeapDump dump1 = mock(HeapDump.class);
+        when(dump1.getTimestamp()).thenReturn(1L);
+        
+        HeapDump dump2 = mock(HeapDump.class);
+        when(dump2.getTimestamp()).thenReturn(2L);
+        
+        List<HeapDump> dumps = new ArrayList<>();
+        dumps.add(dump1);
+        dumps.add(dump2);
+        
+        view.setDumps(dumps);
+        
+        verify(dump1).getTimestamp();
+        verify(dump2).getTimestamp();
+        
+        JListFixture list = frameFixture.list(SwingHeapDumpListView.class.getName() + "_LIST");
+        list.item(0).doubleClick();
+                
+        assertTrue(result[0]);
+        assertEquals(dump2, selectedHeap[0]);
+        
+        result[0] = false;        
+        list.item(1).doubleClick();
+                
+        assertTrue(result[0]);
+        assertEquals(dump1, selectedHeap[0]);
+    }
+}
--- a/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingViewTest.java	Mon Jun 03 11:03:06 2013 +0200
+++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingViewTest.java	Wed Jun 05 20:26:44 2013 +0200
@@ -45,6 +45,7 @@
 
 import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
 
+import org.fest.swing.annotation.GUITest;
 import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
 import org.fest.swing.edt.GuiActionRunner;
 import org.fest.swing.edt.GuiTask;
@@ -53,6 +54,7 @@
 import org.fest.swing.fixture.JLabelFixture;
 import org.fest.swing.fixture.JPanelFixture;
 import org.fest.swing.fixture.JPopupMenuFixture;
+import org.fest.swing.fixture.JToggleButtonFixture;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -61,6 +63,7 @@
 
 import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView.HeapDumperAction;
 import com.redhat.thermostat.vm.heap.analysis.client.core.chart.OverviewChart;
 import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.stats.HeapChartPanel;
@@ -111,6 +114,7 @@
         view = null;
     }
 
+    @GUITest
     @Test
     public void testAddHeapDump() {
         final boolean [] result = new boolean[1];
@@ -151,6 +155,7 @@
         assertEquals(1, resultTimes[0]);
     }
     
+    @GUITest
     @Test
     public void testActivateHeapDump() throws InterruptedException {
         final boolean [] result = new boolean[1];
@@ -220,5 +225,25 @@
         assertTrue(result[0]);
         assertEquals(1, resultTimes[0]);
     }
+    
+    @GUITest
+    @Test
+    public void testHeapDumperActionFired() {
+        
+        final boolean [] result = new boolean[1];
+        view.addDumperListener(new ActionListener<HeapView.HeapDumperAction>() {
+            @Override
+            public void actionPerformed(ActionEvent<HeapDumperAction> actionEvent) {
+                result[0] = true;
+            }
+        });
+        
+        frame.show();
+        
+        JToggleButtonFixture listDupms = frame.toggleButton("LIST_DUMPS_ACTION");
+        listDupms.click();
+
+        assertTrue(result[0]);
+    }
 }