changeset 1714:d9f3dd1eaed2

PR2558: [1.4] Backport - Add tree map view to heap analysis tab Reviewed-by: jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2015-July/014412.html
author Antonio Cesarano <acesaran@redhat.com>
date Thu, 23 Jul 2015 14:03:27 +0200
parents a1f58895a63f
children 23805e2f39be
files vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumpDetailsView.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapTreeMapView.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapTreeMapViewProvider.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/HeapDumpDetailsController.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/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/HeapDumpDetailsControllerTest.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/HeapDetailsSwing.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HistogramConverter.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SquarifiedTreeMap.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SwingHeapTreeMapViewProvider.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapComponent.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapNode.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapPanel.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeProcessor.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ValueFormatter.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/HistogramConverterTest.java vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SquarifiedTreeMapTest.java vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapComponentTest.java vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeMapNodeTest.java vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/TreeProcessorTest.java vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ValueFormatterTest.java
diffstat 29 files changed, 3198 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumpDetailsView.java	Tue Jul 07 12:23:45 2015 -0400
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumpDetailsView.java	Thu Jul 23 14:03:27 2015 +0200
@@ -44,6 +44,7 @@
 
     public abstract void addSubView(LocalizedString title, HeapHistogramView child);
     public abstract void addSubView(LocalizedString title, ObjectDetailsView child);
+    public abstract void addSubView(LocalizedString title, HeapTreeMapView child);
     public abstract void removeSubView(LocalizedString title);
 }
 
--- /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/HeapTreeMapView.java	Thu Jul 23 14:03:27 2015 +0200
@@ -0,0 +1,47 @@
+/*
+ * 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.core;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.core.views.UIComponent;
+import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram;
+
+public abstract class HeapTreeMapView extends BasicView implements UIComponent {
+
+    public abstract void display(ObjectHistogram histogram);
+}
+
--- /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/HeapTreeMapViewProvider.java	Thu Jul 23 14:03:27 2015 +0200
@@ -0,0 +1,48 @@
+/*
+ * 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.core;
+
+import com.redhat.thermostat.annotations.ExtensionPoint;
+import com.redhat.thermostat.client.core.views.ViewProvider;
+
+@ExtensionPoint
+public interface HeapTreeMapViewProvider extends ViewProvider {
+
+    @Override
+    public HeapTreeMapView createView();
+}
+
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/Activator.java	Tue Jul 07 12:23:45 2015 -0400
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/Activator.java	Thu Jul 23 14:03:27 2015 +0200
@@ -57,6 +57,7 @@
 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.HeapTreeMapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
@@ -78,6 +79,7 @@
             HeapViewProvider.class,
             HeapDumpDetailsViewProvider.class,
             HeapHistogramViewProvider.class,
+            HeapTreeMapViewProvider.class,
             ObjectDetailsViewProvider.class,
             ObjectRootsViewProvider.class,
             HeapDumpListViewProvider.class,
@@ -106,6 +108,8 @@
                 Objects.requireNonNull(detailsViewProvider);
                 HeapHistogramViewProvider histogramViewProvider = (HeapHistogramViewProvider) services
                         .get(HeapHistogramViewProvider.class.getName());
+                HeapTreeMapViewProvider treeMapViewProvider = (HeapTreeMapViewProvider) services
+                        .get(HeapTreeMapViewProvider.class.getName());
                 Objects.requireNonNull(histogramViewProvider);
                 ObjectDetailsViewProvider objectDetailsViewProvider = (ObjectDetailsViewProvider) services
                         .get(ObjectDetailsViewProvider.class.getName());
@@ -119,7 +123,7 @@
                 
                 HeapDumperService service = new HeapDumperServiceImpl(appSvc,
                         vmInfoDao, vmMemoryStatDao, heapDao, viewProvider,
-                        detailsViewProvider, histogramViewProvider,
+                        detailsViewProvider, histogramViewProvider, treeMapViewProvider,
                         objectDetailsViewProvider, objectRootsViewProvider,
                         heapDumpListViewProvider, notifier);
                 Dictionary<String, String> properties = new Hashtable<>();
@@ -141,4 +145,3 @@
         tracker.close();
     }
 }
-
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpController.java	Tue Jul 07 12:23:45 2015 -0400
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpController.java	Thu Jul 23 14:03:27 2015 +0200
@@ -69,6 +69,7 @@
 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.HeapTreeMapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView.DumpDisabledReason;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView.HeapDumperAction;
@@ -102,6 +103,7 @@
     private ApplicationService appService;
     private HeapDumpDetailsViewProvider detailsViewProvider;
     private HeapHistogramViewProvider histogramViewProvider;
+    private HeapTreeMapViewProvider treeMapViewProvider;
     private ObjectDetailsViewProvider objectDetailsViewProvider;
     private ObjectRootsViewProvider objectRootsViewProvider;
     private HeapDumpListViewProvider heapDumpListViewProvider;
@@ -114,13 +116,14 @@
                               final ApplicationService appService, HeapViewProvider viewProvider,
                               HeapDumpDetailsViewProvider detailsViewProvider,
                               HeapHistogramViewProvider histogramProvider,
+                              HeapTreeMapViewProvider treeMapProvider,
                               ObjectDetailsViewProvider objectDetailsProvider,
                               ObjectRootsViewProvider objectRootsProvider,
                               HeapDumpListViewProvider heapDumpListViewProvider,
                               ProgressNotifier notifier)
     {
         this(vmMemoryStatDao, vmInfoDao, heapDao, ref, appService, viewProvider,
-             detailsViewProvider, histogramProvider, objectDetailsProvider,
+             detailsViewProvider, histogramProvider, treeMapProvider, objectDetailsProvider,
              objectRootsProvider, heapDumpListViewProvider, new HeapDumper(ref),
              notifier);
     }
@@ -132,6 +135,7 @@
                        HeapViewProvider viewProvider,
                        HeapDumpDetailsViewProvider detailsViewProvider,
                        HeapHistogramViewProvider histogramProvider,
+                       HeapTreeMapViewProvider treeMapProvider,
                        ObjectDetailsViewProvider objectDetailsProvider,
                        ObjectRootsViewProvider objectRootsProvider,
                        HeapDumpListViewProvider heapDumpListViewProvider,
@@ -142,6 +146,7 @@
         this.objectDetailsViewProvider = objectDetailsProvider;
         this.objectRootsViewProvider = objectRootsProvider;
         this.histogramViewProvider = histogramProvider;
+        this.treeMapViewProvider = treeMapProvider;
         this.detailsViewProvider = detailsViewProvider;
         this.appService = appService;
         this.ref = ref;
@@ -355,6 +360,7 @@
         HeapDumpDetailsController controller =
                 new HeapDumpDetailsController(appService, detailsViewProvider,
                                               histogramViewProvider,
+                                              treeMapViewProvider,
                                               objectDetailsViewProvider,
                                               objectRootsViewProvider);
         controller.setDump(dump);
@@ -429,4 +435,3 @@
         }
     }
 }
-
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpDetailsController.java	Tue Jul 07 12:23:45 2015 -0400
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpDetailsController.java	Thu Jul 23 14:03:27 2015 +0200
@@ -49,6 +49,8 @@
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider;
 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.HeapTreeMapView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapTreeMapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
@@ -66,12 +68,14 @@
     private HeapDumpDetailsView view;
     private HeapDump heapDump;
     private HeapHistogramViewProvider histogramViewProvider;
+    private HeapTreeMapViewProvider treeMapViewProvider;
     private ObjectDetailsViewProvider objectDetailsViewProvider;
     private ObjectRootsViewProvider objectRootsViewProvider;
 
-    public HeapDumpDetailsController(ApplicationService appService, HeapDumpDetailsViewProvider viewProvider, HeapHistogramViewProvider histogramProvider, ObjectDetailsViewProvider objectDetailsProvider, ObjectRootsViewProvider objectRootsProvider) {
+    public HeapDumpDetailsController(ApplicationService appService, HeapDumpDetailsViewProvider viewProvider, HeapHistogramViewProvider histogramProvider, HeapTreeMapViewProvider treeMapProvider, ObjectDetailsViewProvider objectDetailsProvider, ObjectRootsViewProvider objectRootsProvider) {
         this.appService = appService;
         this.histogramViewProvider = histogramProvider;
+        this.treeMapViewProvider = treeMapProvider;
         this.objectDetailsViewProvider = objectDetailsProvider;
         this.objectRootsViewProvider = objectRootsProvider;
         view = viewProvider.createView();
@@ -84,6 +88,11 @@
             heapHistogramView.display(heapDump.getHistogram());
             LocalizedString title = translator.localize(LocaleResources.HEAP_DUMP_SECTION_HISTOGRAM);
             view.addSubView(title, heapHistogramView);
+            
+            HeapTreeMapView heapTreeMapView = treeMapViewProvider.createView();
+            heapTreeMapView.display(heapDump.getHistogram());
+            LocalizedString titleTreeMap = translator.localize(LocaleResources.HEAP_DUMP_SECTION_TREEMAP);
+            view.addSubView(titleTreeMap, heapTreeMapView);
         } catch (IOException e) {
             log.log(Level.SEVERE, "unexpected error while reading heap dump", e);
         }
@@ -101,4 +110,3 @@
     }
 
 }
-
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumperServiceImpl.java	Tue Jul 07 12:23:45 2015 -0400
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumperServiceImpl.java	Thu Jul 23 14:03:27 2015 +0200
@@ -36,17 +36,18 @@
 
 package com.redhat.thermostat.vm.heap.analysis.client.core.internal;
 
-import com.redhat.thermostat.common.Filter;
 import com.redhat.thermostat.client.core.NameMatchingRefFilter;
 import com.redhat.thermostat.client.core.controllers.InformationServiceController;
 import com.redhat.thermostat.client.core.progress.ProgressNotifier;
 import com.redhat.thermostat.common.ApplicationService;
+import com.redhat.thermostat.common.Filter;
 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.HeapTreeMapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
@@ -66,6 +67,7 @@
     private HeapViewProvider viewProvider;
     private HeapDumpDetailsViewProvider detailsViewProvider;
     private HeapHistogramViewProvider histogramViewProvider;
+    private HeapTreeMapViewProvider treeMapViewProvider;
     private ObjectDetailsViewProvider objectDetailsViewProvider;
     private ObjectRootsViewProvider objectRootsViewProvider;
 
@@ -78,6 +80,7 @@
             HeapDAO heapDao, HeapViewProvider viewProvider,
             HeapDumpDetailsViewProvider detailsViewProvider,
             HeapHistogramViewProvider histogramViewProvider,
+            HeapTreeMapViewProvider treeMapViewProvider,
             ObjectDetailsViewProvider objectDetailsViewProvider,
             ObjectRootsViewProvider objectRootsViewProvider,
             HeapDumpListViewProvider heapDumpListViewProvider,
@@ -89,6 +92,7 @@
         this.viewProvider = viewProvider;
         this.detailsViewProvider = detailsViewProvider;
         this.histogramViewProvider = histogramViewProvider;
+        this.treeMapViewProvider = treeMapViewProvider;
         this.objectDetailsViewProvider = objectDetailsViewProvider;
         this.objectRootsViewProvider = objectRootsViewProvider;
         this.heapDumpListViewProvider = heapDumpListViewProvider;
@@ -98,7 +102,7 @@
     @Override
     public InformationServiceController<VmRef> getInformationServiceController(VmRef ref) {
         return new HeapDumpController(vmMemoryStatDao, vmInfoDao, heapDao, ref, appService,
-                viewProvider, detailsViewProvider, histogramViewProvider, objectDetailsViewProvider,
+                viewProvider, detailsViewProvider, histogramViewProvider, treeMapViewProvider, objectDetailsViewProvider,
                 objectRootsViewProvider, heapDumpListViewProvider, notifier);
     }
 
@@ -112,4 +116,3 @@
         return ORDER;
     }
 }
-
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/locale/LocaleResources.java	Tue Jul 07 12:23:45 2015 -0400
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/locale/LocaleResources.java	Thu Jul 23 14:03:27 2015 +0200
@@ -77,7 +77,8 @@
     PROCESS_EXITED,
     
     DUMPS_LIST,
-    LIST_DUMPS_ACTION,
+    LIST_DUMPS_ACTION, 
+    HEAP_DUMP_SECTION_TREEMAP,
 
     ;
 
@@ -87,4 +88,3 @@
         return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
     }
 }
-
--- a/vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/locale/strings.properties	Tue Jul 07 12:23:45 2015 -0400
+++ b/vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/locale/strings.properties	Thu Jul 23 14:03:27 2015 +0200
@@ -12,6 +12,7 @@
 
 HEAP_DUMP_SECTION_HISTOGRAM = Histogram
 HEAP_DUMP_SECTION_OBJECT_BROWSER = Object Browser
+HEAP_DUMP_SECTION_TREEMAP = Heap Tree Map
 
 HEAP_DUMP_CLASS_USAGE = Classes Usage
 HEAP_DUMP_HISTOGRAM_COLUMN_CLASS = Class
@@ -35,4 +36,4 @@
 DUMPS_LIST = Available Dumps
 HEAP_DUMP_IN_PROGRESS = dumping...
 HEAP_DUMP_LOADING_IN_PROGRESS = loading...
-PROCESS_EXITED = Process exited.
+PROCESS_EXITED = Process exited.
\ No newline at end of file
--- a/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ActivatorTest.java	Tue Jul 07 12:23:45 2015 -0400
+++ b/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ActivatorTest.java	Thu Jul 23 14:03:27 2015 +0200
@@ -51,6 +51,7 @@
 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.HeapTreeMapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
@@ -86,6 +87,7 @@
         HeapViewProvider viewProvider = mock(HeapViewProvider.class);
         HeapDumpDetailsViewProvider detailsViewProvider = mock(HeapDumpDetailsViewProvider.class);
         HeapHistogramViewProvider histogramViewProvider = mock(HeapHistogramViewProvider.class);
+        HeapTreeMapViewProvider treeMapViewProvider = mock(HeapTreeMapViewProvider.class);
         ObjectDetailsViewProvider objectDetailsViewProvider = mock(ObjectDetailsViewProvider.class);
         ObjectRootsViewProvider objectRootsViewProvider = mock(ObjectRootsViewProvider.class);
         HeapDumpListViewProvider heapDumpListViewProvider = mock(HeapDumpListViewProvider.class);
@@ -99,6 +101,7 @@
         context.registerService(HeapViewProvider.class, viewProvider, null);
         context.registerService(HeapDumpDetailsViewProvider.class, detailsViewProvider, null);
         context.registerService(HeapHistogramViewProvider.class, histogramViewProvider, null);
+        context.registerService(HeapTreeMapViewProvider.class, treeMapViewProvider, null);
         context.registerService(ObjectDetailsViewProvider.class, objectDetailsViewProvider, null);
         context.registerService(ObjectRootsViewProvider.class, objectRootsViewProvider, null);
         context.registerService(HeapDumpListViewProvider.class, heapDumpListViewProvider, null);
@@ -113,7 +116,7 @@
         activator.stop(context);
 
         assertEquals(0, context.getServiceListeners().size());
-        assertEquals(11, context.getAllServices().size());
+        assertEquals(12, context.getAllServices().size());
     }
 
 }
--- a/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpControllerTest.java	Tue Jul 07 12:23:45 2015 -0400
+++ b/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpControllerTest.java	Thu Jul 23 14:03:27 2015 +0200
@@ -36,8 +36,8 @@
 
 package com.redhat.thermostat.vm.heap.analysis.client.core.internal;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.isA;
@@ -49,8 +49,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import java.io.File;
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -85,6 +83,8 @@
 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.HeapTreeMapView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapTreeMapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView.DumpDisabledReason;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView.HeapDumperAction;
@@ -125,6 +125,7 @@
     private HeapViewProvider viewProvider;
     private HeapDumpDetailsViewProvider detailsViewProvider;
     private HeapHistogramViewProvider histogramProvider;
+    private HeapTreeMapViewProvider treeMapProvider;
     private ObjectDetailsViewProvider objectDetailsProvider;
     private ObjectRootsViewProvider objectRootsProvider;
 
@@ -173,6 +174,10 @@
         histogramProvider = mock(HeapHistogramViewProvider.class);
         when(histogramProvider.createView()).thenReturn(histogramView);
 
+        HeapTreeMapView treeMapView = mock(HeapTreeMapView.class);
+        treeMapProvider = mock(HeapTreeMapViewProvider.class);
+        when(treeMapProvider.createView()).thenReturn(treeMapView);
+
         ObjectDetailsView objectView = mock(ObjectDetailsView.class);
         objectDetailsProvider = mock(ObjectDetailsViewProvider.class);
         when(objectDetailsProvider.createView()).thenReturn(objectView);
@@ -209,7 +214,7 @@
         when(ref.getHostRef()).thenReturn(hostRef);
 
         controller = new HeapDumpController(vmDao, vmInfoDao, heapDao, ref, appService,
-                viewProvider, detailsViewProvider, histogramProvider,
+                viewProvider, detailsViewProvider, histogramProvider, treeMapProvider,
                 objectDetailsProvider, objectRootsProvider, heapDumpListViewProvider,
                 heapDumper, notifier);
     }
@@ -222,6 +227,7 @@
         viewProvider = null;
         detailsViewProvider = null;
         histogramProvider = null;
+        treeMapProvider = null;
         objectDetailsProvider = null;
         objectRootsProvider = null;
         appService = null;
@@ -294,7 +300,7 @@
         when(appService.getApplicationCache()).thenReturn(cache);
         VmRef ref = mock(VmRef.class);
         controller = new HeapDumpController(vmDao, vmInfoDao, heapDao, ref, appService,
-                viewProvider, detailsViewProvider, histogramProvider,
+                viewProvider, detailsViewProvider, histogramProvider, treeMapProvider,
                 objectDetailsProvider, objectRootsProvider, heapDumpListViewProvider,
                 heapDumper, notifier);
         
@@ -320,7 +326,7 @@
         when(appService.getApplicationCache()).thenReturn(cache);
         VmRef ref = mock(VmRef.class);
         controller = new HeapDumpController(vmDao, vmInfoDao, heapDao, ref, appService,
-                viewProvider, detailsViewProvider, histogramProvider,
+                viewProvider, detailsViewProvider, histogramProvider, treeMapProvider,
                 objectDetailsProvider, objectRootsProvider, heapDumpListViewProvider,
                 heapDumper, notifier);
         
@@ -341,7 +347,7 @@
         when(vmInfoDao.getVmInfo(ref)).thenReturn(vmInfo);
 
         controller = new HeapDumpController(vmDao, vmInfoDao, heapDao, ref, appService,
-                viewProvider, detailsViewProvider, histogramProvider,
+                viewProvider, detailsViewProvider, histogramProvider, treeMapProvider,
                 objectDetailsProvider, objectRootsProvider, heapDumpListViewProvider,
                 heapDumper, notifier);
 
@@ -563,4 +569,3 @@
     }
 
 }
-
--- a/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpDetailsControllerTest.java	Tue Jul 07 12:23:45 2015 -0400
+++ b/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpDetailsControllerTest.java	Thu Jul 23 14:03:27 2015 +0200
@@ -54,6 +54,8 @@
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider;
 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.HeapTreeMapView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapTreeMapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsView;
@@ -66,6 +68,7 @@
     private HeapDumpDetailsView view;
     private HeapDumpDetailsViewProvider viewProvider;
     private HeapHistogramViewProvider histogramProvider;
+    private HeapTreeMapViewProvider treeMapProvider;
     private ObjectDetailsViewProvider objectDetailsProvider;
     private ObjectRootsViewProvider objectRootsProvider;
 
@@ -79,6 +82,10 @@
         histogramProvider = mock(HeapHistogramViewProvider.class);
         when(histogramProvider.createView()).thenReturn(histogramView);
 
+        HeapTreeMapView treeMapView = mock(HeapTreeMapView.class);
+        treeMapProvider = mock(HeapTreeMapViewProvider.class);
+        when(treeMapProvider.createView()).thenReturn(treeMapView);
+
         ObjectDetailsView objectView = mock(ObjectDetailsView.class);
         objectDetailsProvider = mock(ObjectDetailsViewProvider.class);
         when(objectDetailsProvider.createView()).thenReturn(objectView);
@@ -106,7 +113,7 @@
         when(dump.getHistogram()).thenReturn(histogram);
 
         HeapDumpDetailsController controller = new HeapDumpDetailsController(
-                appService, viewProvider, histogramProvider,
+                appService, viewProvider, histogramProvider, treeMapProvider,
                 objectDetailsProvider, objectRootsProvider);
         controller.setDump(dump);
 
@@ -118,4 +125,3 @@
     }
 
 }
-
--- a/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/Activator.java	Tue Jul 07 12:23:45 2015 -0400
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/Activator.java	Thu Jul 23 14:03:27 2015 +0200
@@ -42,6 +42,7 @@
 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.HeapTreeMapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
@@ -57,6 +58,8 @@
         context.registerService(HeapDumpDetailsViewProvider.class.getName(), detailsViewProvider, null);
         HeapHistogramViewProvider histogramViewProvider = new SwingHeapHistogramViewProvider();
         context.registerService(HeapHistogramViewProvider.class.getName(), histogramViewProvider, null);
+        HeapTreeMapViewProvider treeMapViewProvider = new SwingHeapTreeMapViewProvider();
+        context.registerService(HeapTreeMapViewProvider.class.getName(), treeMapViewProvider, null);    
         ObjectDetailsViewProvider objectDetailsViewProvider = new SwingObjectDetailsViewProvider();
         context.registerService(ObjectDetailsViewProvider.class.getName(), objectDetailsViewProvider, null);
         ObjectRootsViewProvider objectRootsViewProvider = new SwingObjectRootsViewProvider();
--- a/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapDetailsSwing.java	Tue Jul 07 12:23:45 2015 -0400
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapDetailsSwing.java	Thu Jul 23 14:03:27 2015 +0200
@@ -47,6 +47,7 @@
 import com.redhat.thermostat.shared.locale.LocalizedString;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsView;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapTreeMapView;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView;
 
 public class HeapDetailsSwing extends HeapDumpDetailsView implements SwingComponent {
@@ -116,5 +117,15 @@
         }
     }
 
+    @Override
+    public void addSubView(final LocalizedString title, final HeapTreeMapView view) {
+        verifyIsSwingComponent(view);
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                tabPane.insertTab(title.getContents(), null, ((SwingComponent)view).getUiComponent(), null, 0);
+            }
+        });
+    }
+
 }
-
--- /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/HistogramConverter.java	Thu Jul 23 14:03:27 2015 +0200
@@ -0,0 +1,172 @@
+/*
+ * 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.util.ArrayList;
+import java.util.List;
+
+import com.redhat.thermostat.common.utils.DescriptorConverter;
+import com.redhat.thermostat.vm.heap.analysis.common.HistogramRecord;
+import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram;
+
+/**
+ * This class provides statics function to create a {@link TreeMapNode} tree
+ * from an ObjectHistrogram.
+ */
+public class HistogramConverter {
+    
+    /**
+     * The splitter regular expression to split records' className
+     */
+    private static final String SPLIT_REG_EXP = "\\."; //escaped dot
+    
+    /**
+     * Key used to put into nodes the <i>number of instances</i> information 
+     * stored in histogram records.
+     */
+    private static final String NUMBER_OF = "Number Of Instances";  
+    
+    /**
+     * Call this method to create the full TreeMapNode object corresponding to
+     * the {@link ObjectHistogram} histogram given in input.
+     * @param histrogram the histogram to represent as TreeMapNode
+     * @return the resulting tree
+     */
+    public static TreeMapNode convertToTreeMap(ObjectHistogram histrogram) {
+       TreeMapNode root = new TreeMapNode("", 0);
+        
+        List<HistogramRecord> records = new ArrayList<>();
+        records.addAll(histrogram.getHistogram());
+
+        // build the tree from the histogram object
+        processRecords(records, root);
+        // calculates weights for inner nodes
+        fillWeights(root);
+        // collapse nodes with only one child 
+        packTree(root);
+        return root;
+    }
+    
+    /**
+     * This method is responsible for building correctly the histogram 
+     * corresponding tree. For each histogram record, a tree branch is created
+     * but only leaves node have a weight value.
+     * Furthermore, additional information are added to the nodes' map.
+     * 
+     * @param records {@list} of HistogramRecord used to build the tree.
+     * @param root the tree's root.
+     */
+    private static void processRecords(List<HistogramRecord> records, TreeMapNode root) {
+        
+        for (int i = 0; i < records.size(); i++) {
+            
+            TreeMapNode lastProcessed = root;
+            String className = records.get(i).getClassname();
+            
+            // if className is a primitive type it is converted with its full name
+            className = DescriptorConverter.toJavaType(className);
+
+            while (!className.equals("")) {
+               
+                String nodeId = className.split(SPLIT_REG_EXP)[0];
+                
+                TreeMapNode child = lastProcessed.searchNodeByLabel(nodeId);
+                
+                if (child == null) {
+                    child = new TreeMapNode(nodeId, 0);
+                    lastProcessed.addChild(child);
+                }
+                
+                lastProcessed = child;
+
+                className = className.substring(nodeId.length());
+                if (className.startsWith(".")) {
+                    className = className.substring(1);
+                }
+                // removes semicolon from leaves
+                if (className.endsWith(";")) {
+                    className.replace(";", "");
+                }
+            }
+            
+            // at this point lastProcessed references to a leaf
+            lastProcessed.setRealWeight(records.get(i).getTotalSize());
+            lastProcessed.addInfo(NUMBER_OF, 
+                    Long.toString(records.get(i).getNumberOf()));
+        }
+    }
+
+    /**
+     * 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
+     * the children's weights.
+     * 
+     * @param node the subtree's root from which start to calc weights.
+     * @return the node's real weight.
+     */
+    private static double fillWeights(TreeMapNode node) {
+        if (node.getChildren().size() == 0) {
+            return node.getRealWeight();
+        }
+
+        double sum = 0;
+        for (TreeMapNode child : node.getChildren()) {
+            sum += fillWeights(child);
+        }
+        node.setRealWeight(sum);
+        return node.getRealWeight();
+    }
+
+    /**
+     * This method allows to collapse nodes which have only one child.
+     * E.g. nodes labeled <i>com</i> and <i>example</i> are collapsed in the 
+     * parent node, which will have as label <i>com.example</i>.
+     * @param node the subree's root from which start packing.
+     */
+    private static void packTree(TreeMapNode node) {
+        if (node.getChildren().size() == 1) {
+            TreeMapNode child = node.getChildren().get(0);
+            node.setLabel(node.getLabel() + "." + child.getLabel());
+            node.setChildren(child.getChildren());
+            packTree(node);
+        } else {
+            for (TreeMapNode child : node.getChildren()) {
+                packTree(child);
+            }
+        }
+    }
+}
--- /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/SquarifiedTreeMap.java	Thu Jul 23 14:03:27 2015 +0200
@@ -0,0 +1,463 @@
+/*
+ * 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.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+
+
+/**
+ *  This class implements the Squarified algorithm for TreeMaps. Using it, it is 
+ *  possible to associate a rectangle to a {@link TreeMapNode} element and its 
+ *  children.
+ *  <p>
+ *  @see TreeMapNode
+ *  @see TreMapBuilder
+ */
+public class SquarifiedTreeMap {
+    
+    /**
+     * List of node to represent as TreeMap.
+     */
+    private LinkedList<TreeMapNode> elements;
+    
+    /**
+     * Represent the area in which draw nodes.
+     */
+    private Rectangle2D.Double container;
+    
+    private enum DIRECTION {
+        LEFT_RIGHT,
+        TOP_BOTTOM
+    }
+
+    /**
+     * Indicates the drawing direction.
+     */
+    private DIRECTION drawingDir;
+
+    /**
+     * The rectangles area available for drawing.
+     */
+    private Rectangle2D.Double availableArea;
+
+    /**
+     * List of the calculated rectangles.
+     */
+    private List<TreeMapNode> squarifiedNodes;
+
+    /**
+     * List of the current rectangles under processing.
+     */
+    private List<TreeMapNode> currentRow;
+
+    /**
+     * Coordinates on which to draw.
+     */
+    private double lastX = 0;
+    private double lastY = 0;
+
+
+    /**
+     * Constructor.
+     * 
+     * @param d the dimension of the total area in which draw elements.
+     * @param list the list of elements to draw as TreeMap.
+     * 
+     * @throws a NullPointerException if one of the arguments is null.
+     */
+    public SquarifiedTreeMap(Rectangle2D.Double bounds, List<TreeMapNode> list) {
+        this.elements = new LinkedList<>();
+        elements.addAll(Objects.requireNonNull(list));
+        this.container = Objects.requireNonNull(bounds);
+    }
+
+    /**
+     * Invoke this method to calculate the rectangles for the TreeMap.
+     * 
+     * @return a list of node having a rectangle built in percentage to the 
+     * available area.
+     */
+    public List<TreeMapNode> squarify() {
+        initializeArea();
+        prepareData(elements);
+        List<TreeMapNode> row = new ArrayList<>();
+        double w = getPrincipalSide();	
+        squarify(elements, row, w);
+        return getSquarifiedNodes();
+    }
+
+    /**
+     * Calculate recursively the rectangles to draw and their size.
+     * 
+     * @param nodes the list of elements to draw.
+     * @param row the list of current rectangles to process.
+     * @param w the side against which to calculate the rectangles.
+     */
+    private void squarify(LinkedList<TreeMapNode> nodes, List<TreeMapNode> row, double w) {
+        if (nodes.isEmpty() && row.isEmpty()) {
+            // work done
+            return;
+        }
+        if (nodes.isEmpty()) {
+            // no more element to process, just draw current row
+            finalizeRow(row);
+            return;
+        }
+        if (row.isEmpty()) {
+            // add the first element to the row and iterate the process over it
+            row.add(nodes.getFirst());
+            nodes.removeFirst();
+            squarify(nodes, row, w);
+            return;
+        }
+        
+        /*  Greedy step: calculate the best aspect ratio of actual row and the
+         *  best aspect ratio given by adding another rectangle to the row.
+         *  If the current row can not be improved then finalize it
+         *  else add the next element, to improve the global aspect ratio
+         */
+        List<TreeMapNode> expandedRow = new ArrayList<TreeMapNode>(row);
+        expandedRow.add(nodes.getFirst());
+        double actualAspectRatio = bestAspectRatio(row, w);
+        double expandedAspectRatio = bestAspectRatio(expandedRow, w);
+
+        if (!willImprove(actualAspectRatio, expandedAspectRatio)) {
+            finalizeRow(row);
+            squarify(nodes, new ArrayList<TreeMapNode>(), getPrincipalSide());
+        } else {
+            nodes.removeFirst();
+            squarify(nodes, expandedRow, w);
+        }
+    }
+
+    /**
+     * Return the rectangles list.
+     * @return a list of rectangles.
+     */
+    public List<TreeMapNode> getSquarifiedNodes() {
+        return squarifiedNodes;
+    }
+    
+    /**
+     * Initialize the available area used to create the tree map
+     */
+    private void initializeArea() {
+        availableArea = new Rectangle2D.Double(container.getX(), container.getY(), 
+                container.getWidth(), container.getHeight());
+        lastX = 0;
+        lastY = 0;
+        squarifiedNodes = new ArrayList<>();
+        currentRow = new ArrayList<>();
+        updateDirection();
+    }
+    
+    /**
+     * Recalculate the drawing direction.
+     */
+    private void updateDirection() {
+        drawingDir = availableArea.getWidth() > availableArea.getHeight() ? 
+                DIRECTION.TOP_BOTTOM : DIRECTION.LEFT_RIGHT;
+    }
+
+
+    /**
+     * Invert the drawing direction.
+     */
+    private void invertDirection() {
+        drawingDir = drawingDir == DIRECTION.LEFT_RIGHT ? 
+                DIRECTION.TOP_BOTTOM : DIRECTION.LEFT_RIGHT;
+    }
+    
+    /**
+     * Keep the current list of nodes which produced the best aspect ratio
+     * in the available area, draw their respective rectangles and reinitialize 
+     * the current row to draw.
+     * <p>
+     * @param nodes the list of numbers which represent the rectangles' area.
+     * @return the number of Rectangles created.
+     */
+    private void finalizeRow(List<TreeMapNode> nodes) {
+        if (nodes == null || nodes.isEmpty()) {
+            return;
+        }
+        // get the total weight of nodes in order to calculate their percentages
+        double sum = getSum(nodes);
+        // greedy optimization step: get the best aspect ratio for nodes drawn 
+        // on the longer and on the smaller side, to evaluate the best.
+        double actualAR = bestAspectRatio(nodes, getPrincipalSide());
+        double alternativeAR = bestAspectRatio(nodes, getSecondarySide());
+      
+        if (willImprove(actualAR, alternativeAR)) {
+            invertDirection();
+        }
+
+        for (TreeMapNode node: nodes) {
+            // assign a rectangle calculated as percentage of the total weight
+            Rectangle2D.Double r = createRectangle(sum, node.getWeight());
+            node.setRectangle(r);
+            
+            // recalculate coordinates to draw next rectangle
+            updateXY(r);
+
+            // add the node to the current list of rectangles in processing
+            currentRow.add(node);
+        }
+        // recalculate the area in which new rectangles will be drawn and 
+        // reinitialize the current list of node to represent.
+        reduceAvailableArea();
+        newRow();
+    }
+    
+
+    /**
+     * Create a rectangle having area = @param area in percentage of @param sum. 
+     * <p>
+     * For example: assume @param area = 4 and @param sum = 12 and the 
+     * drawing direction is top to bottom. <br>
+     * <p>
+     *   __ __ __ __
+     *  |     |     | 
+     *  |__ __|     |  
+     *  |__ __ __ __|
+     * 
+     * <br>the internal rectangle will be calculated as follow:<br>
+     *  {@code height = (4 / 9) * 3} <--note that the principal side for actual  
+     *  drawing direction is 3.
+     *  <br>Now it is possible to calculate the width:<br>
+     *  {@code width = 4 / 1.3} <-- note this is the height value
+     *  
+     * <p>
+     * @param sum the total size of all rectangles in the actual row.
+     * @param area this Rectangle's area.
+     * @return the Rectangle which correctly fill the available area.
+     */
+    private Rectangle2D.Double createRectangle(Double sum, Double area) {
+        double side = getPrincipalSide();
+        double w = 0;
+        double h = 0;
+        
+        //don't want division by 0
+        if (validate(area) == 0 || validate(sum) == 0 || validate(side) == 0) {
+            return new Rectangle2D.Double(lastX, lastY, 0, 0);
+        }
+        
+        // calculate the rectangle's principal side relatively to the container 
+        // rectangle's principal side.
+        if (drawingDir == DIRECTION.TOP_BOTTOM) {
+            h = (area / sum) * side;
+            w = area / h;
+        } else {
+            w = (area / sum) * side;
+            h = area / w;
+        }        
+        return new Rectangle2D.Double(lastX, lastY, w, h);
+    }
+    
+    /**
+     * Check if a double value is defined as Not a Number and sets it to 0.
+     * @param d the value to check.
+     * @return the checked value: 0 if the given number is NaN, else the number
+     * itself.
+     */
+    private double validate(double d) {
+        if (d == Double.NaN) {
+            d = 0;
+        }
+        return d;
+    }
+
+    /**
+     * Check in which direction the rectangles have to be drawn.
+     * @return the side on which rectangles will be created.
+     */
+    private double getPrincipalSide() {
+        return drawingDir == DIRECTION.LEFT_RIGHT ? 
+                availableArea.getWidth() : availableArea.getHeight();
+    }
+
+    /**
+     * 
+     * @return the secondary available area's side.
+     */
+    private double getSecondarySide() {
+        return drawingDir == DIRECTION.LEFT_RIGHT ? 
+                availableArea.getHeight() : availableArea.getWidth();
+    }
+
+    /**
+     * Sum the elements in the list.
+     * @param nodes the list which contains elements to sum.
+     * @return the sum of the elements.
+     */
+    private double getSum(List<TreeMapNode> nodes) {
+        int sum = 0;
+        for (TreeMapNode n : nodes) {
+            sum += n.getWeight();
+        }
+        return sum;
+    }
+
+    /**
+     * Recalculate the origin to draw next rectangles.
+     * @param r the rectangle from which recalculate the origin.
+     */
+    private void updateXY(Rectangle2D.Double r) {
+        if (drawingDir == DIRECTION.LEFT_RIGHT) {
+            //lastY doesn't change
+            lastX += r.width; 
+        } else {
+            //lastX doesn't change
+            lastY += r.height;
+        }
+    }
+
+    /**
+     * Initialize the origin at the rectangle's origin.
+     * @param r the rectangle used as origin source.
+     */
+    private void initializeXY(Rectangle2D.Double r) {
+        lastX = r.x;
+        lastY = r.y;
+    }
+
+    /**
+     * Reduce the size of the available rectangle. Use it after the current 
+     * row's closure.
+     */
+    private void reduceAvailableArea() {
+        if (drawingDir == DIRECTION.LEFT_RIGHT) {
+            // all rectangles inside the row have the same height
+            availableArea.height -= currentRow.get(0).getRectangle().height;
+            availableArea.y = lastY + currentRow.get(0).getRectangle().height;
+            availableArea.x = currentRow.get(0).getRectangle().x;
+        } else {
+            // all rectangles inside the row have the same width
+            availableArea.width -= currentRow.get(0).getRectangle().width;
+            availableArea.x = lastX + currentRow.get(0).getRectangle().width;
+            availableArea.y = currentRow.get(0).getRectangle().y;
+        }
+        updateDirection();
+        initializeXY(availableArea);
+    }
+    
+    /**
+     * Close the current row and initialize a new one.
+     */
+    private void newRow() {
+        squarifiedNodes.addAll(currentRow);
+        currentRow = new ArrayList<>();
+    }
+
+    /**
+     * Calculate the aspect ratio for all the rectangles in the list and
+     * return the max of them.
+     * @param row the list of rectangles.
+     * @param side the side against which to calculate the the aspect ratio.
+     * @return the max aspect ratio calculated for the row.
+     */
+    private double bestAspectRatio(List<TreeMapNode> row, double side) {
+        if (row == null || row.isEmpty()) {
+            return Double.MAX_VALUE;
+        }
+        double sum = getSum(row);
+        double max = 0;
+        // calculate the aspect ratio against the main side, and also its inverse.
+        // this is because aspect ratio of rectangle 6x4 can be calculated as 
+        // 6/4 but also 4/6. Here the aspect ratio has been calculated as 
+        // indicated in the Squarified algorithm.
+        for (TreeMapNode node : row) {
+            double m1 = (Math.pow(side, 2) * node.getWeight()) / Math.pow(sum, 2);
+            double m2 = Math.pow(sum, 2) / (Math.pow(side, 2) * node.getWeight());
+            double m = Math.max(m1, m2);
+
+            if (m > max) {
+                max = m;
+            }
+        }
+        return max;
+    }
+
+    
+    /**
+     * Prepare the elements in the list, sorting them and transforming them
+     * proportionally the given dimension.
+     * @param dim the dimension in which rectangles will be drawn.
+     * @param elements the list of elements to draw.
+     * @return the list sorted and proportioned to the dimension.
+     */
+    private void  prepareData(List<TreeMapNode> elements) {
+        if (elements == null || elements.isEmpty()) {
+            return;
+        }
+        TreeMapNode.sort(elements);
+        double totArea = availableArea.width * availableArea.height;
+        double sum = getSum(elements);
+        
+        // recalculate weights in percentage of their sum
+        for (TreeMapNode node : elements) {
+            int w = (int) Math.round((node.getWeight()/sum) * totArea);
+            node.setWeight(w);
+        }
+    }
+
+    /**
+     * This method check which from the values in input, that represent 
+     * rectangles' aspect ratio, produces more approximatively a square.
+     * It checks if one of the aspect ratio values gives a value nearest to 1 
+     * against the other, which means that width and height are similar.
+     * @param actualAR the actual aspect ratio
+     * @param expandedAR the aspect ratio to evaluate
+     * @return false if the actual aspect ratio is better than the new one, 
+     * else true.
+     */
+    private boolean willImprove(double actualAR, double expandedAR) {
+        if (actualAR == 0) {
+            return true;
+        }
+        if (expandedAR == 0) {
+            return false;
+        }
+        // check which value is closer to 1, the square's aspect ratio
+        double v1 = Math.abs(actualAR - 1);
+        double v2 = Math.abs(expandedAR - 1);       
+        return v1 > v2;
+    }
+}
--- /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/SwingHeapTreeMapViewProvider.java	Thu Jul 23 14:03:27 2015 +0200
@@ -0,0 +1,49 @@
+/*
+ * 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 com.redhat.thermostat.vm.heap.analysis.client.core.HeapTreeMapView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapTreeMapViewProvider;
+
+public class SwingHeapTreeMapViewProvider implements HeapTreeMapViewProvider {
+
+    @Override
+    public HeapTreeMapView createView() {
+        return new TreeMapPanel();
+    }
+
+}
--- /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/TreeMapComponent.java	Thu Jul 23 14:03:27 2015 +0200
@@ -0,0 +1,676 @@
+/*
+ * 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.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.font.FontRenderContext;
+import java.awt.geom.Rectangle2D;
+import java.util.Objects;
+import java.util.Stack;
+
+import javax.swing.BorderFactory;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.border.Border;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
+import javax.swing.border.LineBorder;
+
+import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram;
+
+/**
+ * This class allows to represent a hierarchical data structure as a TreeMap.
+ * It extends {@link JComponent} so it can be used like usual Swing objects.
+ *
+ */
+public class TreeMapComponent extends JComponent {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * TreeMap's graphic root.
+     */
+    Comp mainComp;
+
+    /**
+     * Label Object to clone for faster initialization.
+     */
+    private Label cachedLabel;
+
+    /**
+     * The tree to render as TreeMap.
+     */
+    TreeMapNode tree;
+
+    /**
+     * Horizontal and vertical padding for nested component.
+     */
+    private final int X_PADDING = TreeProcessor.X_PADDING;
+    private final int Y_PADDING = TreeProcessor.Y_PADDING;
+
+    /**
+     * Min size for rectangles' sides. rectangles having one or both sides less
+     * than MIN_SIDE pixels will be not drawn.
+     */
+    private final int MIN_SIDE = 1;
+
+    /**
+     * Default value for a TreeMap component.
+     */
+    private static final String TITLE = "";
+
+    /**
+     * TreeMap UI Constraint.
+     */
+    public static final int SIMPLE = 0;
+    public static final int FLAT = 1;
+    public static final int ETCHED_LOWERED = 2;
+    public static final int ETCHED_RAISED = 3;
+
+    /**
+     * Stores the chosen UI mode.
+     */
+    private int borderStyle = ETCHED_LOWERED;
+
+    /**
+     * The components' border
+     */
+    private Border defaultBorder;
+
+    /**
+     * Font and size for this component's label.
+     */
+    private int FONT_SIZE = 8;
+    private Font FONT = (Font) UIManager.get("thermostat-default-font");
+
+
+    /**
+     * Variable in which store last resize dimension.
+     */
+    private Dimension lastDim;
+
+    /**
+     * Variable in which store last resize event call time.
+     */
+    private static long lastCall = 0;
+
+    /**
+     * Wait time in millisec to resize the TreeMap.
+     */
+    private final int MIN_DRAGGING_TIME = 60;
+
+
+    /**
+     * Stack containing the zoom calls on the TreeMap.
+     */
+    private Stack<TreeMapNode> zoomStack;
+
+    /**
+     * This object stores the last clicked rectangle in the TreeMap, in order to 
+     * repaint it when another rectangle will be selected.
+     */
+    private static Comp lastClicked;
+    
+    /**
+     * Constructor which creates a TreeMapComponent by an histogram object.
+     * @param histogram the histogram to represent as tree map.
+     */
+    public TreeMapComponent(ObjectHistogram histogram) {
+        this(HistogramConverter.convertToTreeMap(histogram), new Dimension());
+    }
+
+    /**
+     * Constructor. It draw a TreeMap of the given tree in according to the 
+     * {@Dimension} object in input.
+     * 
+     * @param tree the tree to represent as TreeMap.
+     * @param d the dimension the TreeMap will fulfill.
+     * 
+     * @throws NullPointerException if one of the parameters is null
+     */
+    public TreeMapComponent(TreeMapNode tree, Dimension d) {
+        super();
+        Objects.requireNonNull(tree);
+        Objects.requireNonNull(d);
+        this.tree = tree;
+        lastDim = getSize();
+        this.zoomStack = new Stack<>();
+        this.zoomStack.push(this.tree);
+
+        // 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);
+
+        // calculate rectangles of tree's subtrees
+        TreeProcessor.processTreeMap(tree, area);
+
+        drawTreeMap(tree); 
+
+        addResizeListener(this);        
+        repaint();
+    }
+
+    /**
+     * This method returns the root of the tree showed ad TreeMap.
+     * @return the TreeMap's root node.
+     */
+    public TreeMapNode getTreeMapRoot() {
+        return this.tree;
+    }
+
+    /**
+     * This method is responsible for the TreeMap drawing process.
+     * @param tree the tree to represent as TreeMap.
+     */
+    private void drawTreeMap(TreeMapNode tree) {
+        // draw root
+        drawMainComp(tree);
+        setBorderStyle(borderStyle);
+        
+        // draw subtrees nested in children 
+        for (TreeMapNode child : tree.getChildren()) {
+            drawSubTree(child, mainComp);
+        }
+        // setup this component
+        prepareGUI();
+    }
+
+    /**
+     * This method prepares the layout for this component. 
+     */
+    private void prepareGUI() {
+        setLayout(new BorderLayout());
+        setBounds(mainComp.getBounds());
+        setBorder(null);
+        add(mainComp, BorderLayout.CENTER);
+        revalidate();
+        repaint();
+    }
+
+    /**
+     * This method prepares the main component which is the parent object where 
+     * sub components will be placed. 
+     * @param tree the tree's root used to prepare the main component.
+     */
+    private void drawMainComp(TreeMapNode tree) {
+        mainComp = new Comp();
+        mainComp.setLayout(null);
+        mainComp.setBounds(tree.getRectangle().getBounds());        
+        mainComp.setNode(tree);
+        cachedLabel = new Label(TITLE + tree.getLabel());        
+        addLabelIfPossible(TITLE + tree.getLabel(), mainComp);
+    }
+
+    /**
+     * Create a TreeMapComp from the given node. The component is not 
+     * instantiated as a new component but is cloned from an existing one, in 
+     * order to improve performance.
+     * 
+     * @param node the node to represent as a component.
+     * @return the component representing the given node.
+     */
+    private Comp renderizeNode(TreeMapNode node) {
+        // if the rectangle's node is too small to be viewed, don't draw it.
+        if (node.getRectangle().getWidth() <= MIN_SIDE || 
+                node.getRectangle().getHeight() <= MIN_SIDE) {
+            return null;
+        }
+
+        Comp comp = (Comp) mainComp.clone();
+        comp.setBounds(node.getRectangle().getBounds());
+
+        return comp;
+    }
+
+    /**
+     * This method checks if the given container has enough space to instantiate
+     * a Label in it. If yes, a Label is cloned from an existing one, in order 
+     * to improve performance. If not, it exits.
+     * 
+     * @param s the label text.
+     * @param cont the parent container which will contain the new label.
+     * @return the cloned label.
+     */
+    private Label addLabelIfPossible(String s, Container cont) {
+        if (s == null || s.equals("")) {
+            return null;
+        }
+        int componentW = cont.getSize().width;
+        int componentH = cont.getSize().height;
+        // get the rectangle associated to the area needed for the label's text
+        Rectangle fontArea = FONT.getStringBounds(s, 
+                new FontRenderContext(FONT.getTransform(),
+                        false, false)).getBounds();
+
+        // if the container is greater than the label, add it to the container
+        if (componentW > fontArea.width && componentH > fontArea.height) {
+            Label label = (Label) cachedLabel.clone();
+            label.setBounds(5, 1, cont.getWidth(), fontArea.height);
+            label.setText(s);
+            cont.add(label);
+            return label;
+        }
+        return null;
+    }
+
+    /**
+     * Draw the whole {@param tree}'s subtree inside the given component.
+     * @param tree the tree to draw
+     * @param parent the component in which build the tree.
+     */
+    private void drawSubTree(TreeMapNode tree, JComponent parent) {
+        Comp comp = addCompIfPossible(tree, parent);
+
+        // if space was enough to draw a component, try to draw its children
+        if (comp != null) {
+            comp.setNode(tree);
+            for (TreeMapNode child : tree.getChildren()) {
+                drawSubTree(child, comp);
+            }
+        }
+    }
+
+    /**
+     * Create and add to the {@link Container} given in input a 
+     * {@link ComponentResized} listener.
+     * @param c the container in to assign the listener.
+     */
+    private void addResizeListener(final Container container) {
+        ComponentAdapter adapter = new ComponentAdapter() {
+            public void componentResized(ComponentEvent e) {
+                // if enough time is passed from the last call, redraw the TreeMap
+                if (canResize(MIN_DRAGGING_TIME)) {
+                    Dimension newDim = container.getSize();
+
+                    if (isChangedSize(newDim)) {
+                        redrawTreeMap(); 
+                    }
+                } 
+            }            
+        };
+        container.addComponentListener(adapter);
+    }
+
+    /**
+     * This method checks if the given container has enough space to instantiate
+     * a TreeMapComp object in it. If yes, a Label is cloned from an existing 
+     * one, in order to improve performance. If not, it exits.
+     * 
+     * @param node the node to draw and add to the given container.
+     * @param cont the parent container which will contain the new component.
+     * @return true if the component was created and added, else false.
+     */
+    private Comp addCompIfPossible(TreeMapNode node, Container cont) {
+        Rectangle2D rect = node.getRectangle();
+        // if the ndoe's rectangle is smaller than the container, it is added
+        if (cont.getWidth() > rect.getWidth() + X_PADDING && 
+                cont.getHeight() > rect.getHeight() + Y_PADDING) {
+
+            Comp toReturn = renderizeNode(node);
+            if (toReturn == null) {
+                return null;
+            }
+            addLabelIfPossible(TITLE + node.getLabel(), toReturn);
+
+            // leaves some space from the parent's origin location
+            Point loc = toReturn.getLocation();
+            loc.x += X_PADDING;
+            loc.y += Y_PADDING;
+            toReturn.setLocation(loc);
+
+            cont.add(toReturn);
+            return toReturn;
+        }
+        return null;
+    }
+
+
+    /**
+     * This method recalculates and redraws the TreeMap in according to the size
+     * of this component and the actual {@link TreeMapNode} object.
+     */
+    private void redrawTreeMap() {
+        Rectangle2D.Double newArea = tree.getRectangle();
+        // give to the root node the size of this object so it can be recalculated
+        newArea.width = getSize().width;
+        newArea.height = getSize().height;
+
+        // recalculate the tree
+        TreeProcessor.processTreeMap(tree, newArea);
+
+        removeAll();
+        drawTreeMap(tree);        
+    }
+
+    /**
+     * Zoom the TreeMap on the given node.
+     * @param node the new TreeMap's root.
+     */
+    public void zoomIn(TreeMapNode node) {
+        if (node != null && node != this.tree && !zoomStack.contains(node)) {
+            zoomStack.push(node);
+            tree = node;
+            redrawTreeMap();
+        } 
+    }
+
+    /**
+     * Zoom out the view to the last zoom level, until the original root is 
+     * reached.
+     */
+    public void zoomOut() {
+        if (zoomStack.size() > 1) {
+            zoomStack.pop();
+            tree = zoomStack.peek();
+            redrawTreeMap();
+        }
+    }
+
+    /**
+     * Zoom out the view directly to the original root.
+     */
+    public void zoomFull() {
+        if (zoomStack.size() > 1) {
+            clearZoomCallsStack();
+            tree = zoomStack.peek();
+            redrawTreeMap();
+        }
+    }
+
+    /**
+     * Returns the list of zoom operation calls.
+     * @return the stack that holds the zoom calls.
+     */
+    public Stack<TreeMapNode> getZoomCallsStack() {
+        return zoomStack;
+    }
+
+    /**
+     * Clear the zoom calls of this object leaving the stack with just the root.
+     */
+    public void clearZoomCallsStack() {
+        while (zoomStack.size() > 1) {
+            zoomStack.pop();
+        }
+    }
+
+    /**
+     * check if last resize operation was called too closer to this
+     * one. If so, ignore it: the container is being dragged. 
+     * 
+     * @return true if this method is invoked at distance of 
+     * MIN_DRAGGING_TIME millisec, else false. 
+     */
+    private boolean canResize(int millisec) {
+        long time = System.currentTimeMillis();
+        if (time - lastCall >= millisec) {
+            lastCall = time;
+            return true;
+        }
+        return false;
+    }
+
+
+    /**
+     * Check if the dimension given in input differs from the last one stored
+     * by 2. 
+     * @param newDim the new dimension to check.
+     * @return true if the dimensions are different, else false.
+     */
+    private boolean isChangedSize(Dimension newDim) {
+        int minResizeDim = 2;
+        int deltaX = Math.abs(newDim.width - lastDim.width);
+        int deltaY = Math.abs(newDim.height - lastDim.height);
+
+        if (deltaX > minResizeDim || deltaY > minResizeDim) {
+            lastDim = newDim;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Switch the component's visualization mode to the one given in input. 
+     * Use static constraints to set correctly a visualization mode.
+     * @param constraint the UI visualization mode to set.
+     */
+    public void setBorderStyle(int UIMode) {
+        this.borderStyle = UIMode;
+        switch (borderStyle) {
+            case 1 : {
+                defaultBorder = new EmptyBorder(0, 0, 0, 0);
+                break;
+            }    
+            case 2 : {                
+                defaultBorder = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED, Color.white, Color.darkGray);
+                break;
+            }
+            case 3 : {
+                defaultBorder = BorderFactory.createEtchedBorder(EtchedBorder.RAISED, Color.white, Color.darkGray);
+                break;
+            }
+            default : {
+                defaultBorder = new LineBorder(Color.black, 1);
+                break;
+            }
+        }
+        applyBorderToSubtree(mainComp);
+    }
+    
+    /**
+     * Traverse recursively the tree from the given component applying to it 
+     * the default border.
+     * @param comp the subtree's root from which apply the border style.
+     */
+    private void applyBorderToSubtree(Comp comp) {
+        comp.setBorder(defaultBorder);
+        Component[] children = comp.getComponents();
+        for (int i = 0; i < children.length; i++) {
+            if (children[i] instanceof Comp) {
+                applyBorderToSubtree((Comp) children[i]);
+            }
+        }
+    }
+
+    /**
+     * Return the last clicked component inside the TreeMap.
+     * @return the last clicked {@Comp} object.
+     */
+    public Comp getClickedComponent() {
+        return lastClicked;
+    }
+
+    /**
+     * This class provides an extension of {@link JLabel} which main 
+     * characteristic is to implement the {@link Cloneable} interface in order
+     * to make his creation faster then JLabel class.
+     */
+    class Label extends JLabel implements Cloneable {
+        private static final long serialVersionUID = 1L;
+
+        public Label(String s) {
+            super(s);
+            setFont(FONT);
+            setBounds(0, 0, getPreferredSize().width, FONT_SIZE);
+        }
+
+        @Override
+        protected JLabel clone() {
+            Label clone = new Label("");
+            clone.setFont(getFont());
+            clone.setText(getText());
+            clone.setBackground(getBackground());
+            clone.setBounds(getBounds());
+            clone.setBorder(getBorder());
+            return clone;
+        }
+    }    
+
+    /**
+     * This class provides an extension of {@link JComponent} which main 
+     * characteristic is to implement {@link Cloneable} interface in order to
+     * make his creation faster. <br>
+     * It also provides some action listeners that allow to select it, performing
+     * zoom operations for the treemap.
+     */
+    class Comp extends JComponent implements Cloneable {
+
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * The node represented by this component.
+         */
+        private TreeMapNode node;
+
+        /**
+         * The background color. It depends by the node's depth.
+         */
+        private Color color;
+
+        /**
+         * Reference to this.
+         */
+        private Comp thisComponent;
+
+        public Comp() {
+            super();
+            thisComponent = this;
+            addClickListener(this);
+        }
+
+        @Override
+        public Comp clone() {
+            Comp clone = new Comp();
+            clone.setBounds(getBounds());
+            clone.setBorder(getBorder());
+            clone.setLayout(getLayout());
+            clone.setOpaque(true);
+            return clone;
+        }
+
+        public void setNode(TreeMapNode node) {
+            this.node = node;
+            this.color = node.getColor();
+            ValueFormatter f = new ValueFormatter(this.node.getRealWeight());
+            this.setToolTipText(this.node.getLabel() + " - " + f.format());
+        }
+        
+        public TreeMapNode getNode() {
+            return this.node;
+        }
+
+        public Color getColor() {
+            return this.color;
+        }
+
+        public void setColor(Color c) {
+            this.color = c;
+        }
+
+        @Override
+        public void paintComponent(Graphics g) {
+            super.paintComponent(g); 
+            if (this.color != null) {
+                g.setColor(color);
+                g.fillRect(0, 0, getWidth(), getHeight());
+            }
+        }   
+
+        /**
+         * Add a mouse listener to this component. It allows to select it and
+         * zoom it. 
+         * @param component the component which will have the mouse listener.
+         */
+        private void addClickListener(final JComponent component) {
+            MouseListener click = new MouseAdapter() {
+                @Override
+                public void mousePressed(MouseEvent e) {
+                    // one left click select the rectangle
+                    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)) {
+                            zoomIn(getNode());
+                        } else if (SwingUtilities.isRightMouseButton(e)) {
+                            zoomOut();
+                        } else {
+                            zoomFull();
+                        }
+                    }
+                }
+            };
+            component.addMouseListener(click);
+        }
+
+        /**
+         * This method gives a darker color to this component and restore the
+         * original color to the last selected component.
+         */
+        private void selectComp() {
+            if (lastClicked != null) {
+                lastClicked.setColor(lastClicked.getColor().brighter());
+                lastClicked.repaint();
+            } 
+            lastClicked = thisComponent;
+            setColor(getColor().darker());
+            repaint();
+        }
+    }
+}
+
+
+
+
+
--- /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/TreeMapNode.java	Thu Jul 23 14:03:27 2015 +0200
@@ -0,0 +1,450 @@
+/*
+ * 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.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class provide a tree recursive implementation used in
+ * {@link SquarifiedTreeMap}. It contains a reference to the parent node and to
+ * a node list, which represent the node's children. It is also 
+ * possible to store generic information inside the node using a {@link Map} 
+ * object. Furthermore, the main property of this class is the chance to have a
+ * weight for the node and associate to it a {@link Rectangle2D.Double} object.
+ * 
+ * <p>When an instance of this class is created, it will automatically be 
+ * assigned a unique id.
+ * 
+ * <p>By default, this class' comparator is based on the nodes' weight.
+ * 
+ * <p>A static Quick Sort algorithm implementation is also provided by this 
+ * class.
+ * 
+ * @see Rectangle2D.Double
+ */
+public class TreeMapNode {
+        
+    /**
+     * Counter for assign unique id to nodes.
+     */
+    private static int idCounter = 0;
+
+    /**
+     * The rectangle which will graphically represent this node.
+     */
+    private Rectangle2D.Double rectangle;
+
+    /**
+     * This node's id.
+     */
+    private int id;
+    
+    /**
+     * A Map in which store information for this node.
+     */
+    private Map<String, String> info;
+    
+    /**
+     * Reference to the parent.
+     */
+    private TreeMapNode parent;
+    
+    /**
+     * Reference to children.
+     */
+    private List<TreeMapNode> children;
+    
+    /**
+     * The node's weight.
+     */
+    private double weight;
+    
+    /**
+     * The node's label. It can be the same of another node.
+     */
+    private String label;
+    
+    /**
+     * The node's weight which has been set inside the constructor. Note that
+     * this value can be assigned just one time, using the constructor. All 
+     * operations which refers to node's weight work on the weight field, that 
+     * is used to make calcs.
+     */
+    private double realWeight;
+    
+    /**
+     * This flag indicates if weight value can be a non positive number.
+     */
+    static boolean allowNonPositiveWeight = false;
+    
+    /**
+     * The color of this node.
+     */
+    private Color color;
+    
+    /**
+     * Colors available on which iterate
+     */
+    static final Color[] colors = {
+            Color.decode("#FACED2"), // red
+            Color.decode("#B9D6FF"), // blue
+            Color.decode("#E5E5E5"), // grey
+            Color.decode("#FFE7C7"), // orange
+            Color.decode("#ABEBEE"), // aqua
+            Color.decode("#E4D1FC"), // purple
+            Color.decode("#FFFFFF"), // white
+            Color.decode("#CDF9D4")  // green
+    };
+    
+    public final Color START_COLOR = colors[0];
+    
+    /**
+     * 
+     * Constructor that allow to set the nodes' real weight. Others fields are 
+     * initialized to their default value.
+     * It automatically set the node's id.
+     *
+     * <p>
+     * @param realWeight the nodes real weight, which will be not affected 
+     * during node processing.
+     * 
+     */
+    public TreeMapNode(double realWeight) {
+        this("", realWeight);
+    }
+
+    /**
+     * 
+     * Constructor that allow to set the nodes' real weight and the label. 
+     * Others fields are initialized to their default value.
+     * It automatically set the node's id.
+     *
+     * <p>
+     * @param label the node's label.
+     * @param realWeight the nodes real weight, which will be not affected 
+     * during node processing.
+     * 
+     */
+    public TreeMapNode(String label, double realWeight) {
+        this.id = idCounter++;
+        this.label = label;
+        this.parent = null;
+        this.children = new ArrayList<TreeMapNode>();
+        this.rectangle = new Rectangle2D.Double();
+        this.info = new HashMap<String, String>();
+        this.weight = realWeight;
+        this.realWeight = realWeight;
+    }
+
+    /**
+     * Return the id of this object.
+     * @return the id automatically assigned at this object initialization.
+     */
+    public int getId() {
+        return this.id;
+    }
+    
+    /**
+     * Set this node's label.
+     * @param newLabel the new label to set.
+     */
+    public void setLabel(String newLabel) {
+        this.label = newLabel;
+    }
+    
+    /**
+     * Return the label of this object.
+     * @return the label assigned at instantiation time to this object.
+     */
+    public String getLabel() {
+        return this.label;
+    }
+
+    /**
+     * Return the reference to the node parent of this object.
+     * @return the parent of this node. It can be null.
+     */
+    public TreeMapNode getParent() {
+        return this.parent;
+    }
+
+    /**
+     * Set as parent of this object the node given in input.
+     * @param parent the new parent of this object. No checks are made for null
+     * value.
+     */
+    public void setParent(TreeMapNode parent) {
+        this.parent = parent;
+    }
+
+    /**
+     * Return the list of nodes representing this node's children.
+     * @return a list of {@link TreeMapNode} objects.
+     */
+    public List<TreeMapNode> getChildren() {
+        return this.children;
+    }
+    
+    /**
+     * Set as children list of this object the list given in input.
+     * @param children the new list of children for this node.
+     */
+    public void setChildren(List<TreeMapNode> children) {
+        this.children = children;
+        for (TreeMapNode child : this.children) {
+            child.setParent(this);
+        }
+    }
+
+    /**
+     * Return the {@link Map} object containing all information of this node.
+     * @return a {@link Map} object.
+     */
+    public Map<String, String> getInfo() {
+        return this.info;
+    }
+    
+    /**
+     * Store the given information into this object.
+     * @param key the key searching value for the information to store.
+     * @param value the information to store into this object.
+     * @return the old value for the given key.
+     */
+    public String addInfo(String key, String value) {
+        return this.info.put(key, value);
+    }
+
+    /**
+     * Return the information stored in this object, corresponding to the key 
+     * given in input.
+     * @param key the key value for the search information.
+     * @return the corresponding value for the given key.
+     */
+    public String getInfo(String key) {
+        return this.info.get(key);
+    }
+
+    /**
+     * Add the object given in input to the children list of this object. It 
+     * also add this object as its parent.
+     * @param child the new child to add at this object.
+     */
+    public void addChild(TreeMapNode child) {
+        if (child != null) {
+            this.children.add(child);
+            child.setParent(this);
+        }
+    }
+
+    @Override
+    /**
+     * Return a {@link String}  representing this object.
+     */
+    public String toString() {
+        return  getClass().getSimpleName() + " [" + "label = " + getLabel() + 
+                "; weight =" + getRealWeight() + 
+                "; 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 
+     * ({@link Double.Nan}), this method returns a value that can be transformed
+     * by external objects, so if you need the real weight you have to
+     * invoke getrealWeight().
+     * 
+     * @return the node's weight.
+     */
+    public double getWeight() {
+        if ((weight <= 0 || weight == Double.NaN) && !allowNonPositiveWeight) {
+            return realWeight;
+        }
+        return this.weight;
+    }
+    
+    /**
+     * Use this method to retrieve the real weight assigned to this node.
+     * @return the weight corresponding to this node.
+     */
+    public double getRealWeight() {
+        return this.realWeight;
+    }
+    
+    
+    /**
+     * Use this method to set the real weight of this node.
+     */
+    public void setRealWeight(double w) {
+        this.realWeight = w;
+    }
+
+    /**
+     * Set the weight of this object. If a negative value is given, it is set 
+     * automatically to 0.
+     * @param weight the new weight for this object.
+     */
+    public void setWeight(int w) {
+        this.weight = w < 0 && !allowNonPositiveWeight ? 0 : w;
+    }
+
+
+    /**
+     * Return the rectangle representing this object.
+     * @return a {@link Rectangle2D.Double} object.
+     */
+    public Rectangle2D.Double getRectangle() {
+        if (this.rectangle == null) {
+            throw new RuntimeException();
+        }
+        return this.rectangle;
+    }
+
+    /**
+     * Set a new rectangle for this object.
+     * @param rectangle the new rectangle that represent this node.
+     */
+    public void setRectangle(Rectangle2D.Double rectangle) {
+        this.rectangle = rectangle;
+    }    
+
+    /**
+     * 
+     * @return true if non positive value can be used as weight, else false.
+     */
+    public static boolean isAllowNonPositiveWeight() {
+        return allowNonPositiveWeight;
+    }
+
+    /**
+     * Set this value to false and nodes will be not able to manage non positive
+     * values for weight field, otherwise set to true.
+     * @param allowed the flag value for managing non positive values as weight
+     */
+    public static void setAllowNonPositiveWeight(boolean allowed) {
+        allowNonPositiveWeight = allowed;
+    }
+
+    /**
+     * This method assess if the rectangle associated to this node is drawable,
+     * which means that its sides are greater than 1.
+     * @return true if the rectangle associated to this node  is drawable, 
+     * else false.
+     */
+    public boolean isDrawable() {
+        if (rectangle.width >= 1 && rectangle.height >= 1) {
+            return true;
+        }
+        return false;
+    }
+    
+    public Color getColor() {
+        return color;
+    }
+
+    public void setColor(Color color) {
+        this.color = color;
+    }
+    
+    /**
+     * Returns this node's next color.
+     * @return the color which came after this node's color in the color list.
+     * If this node has no color assigned then the START_COLOR is returned.
+     */
+    public Color getNextColor() {
+        if (this.color != null) {
+            for (int i = 0; i < colors.length; i++) {
+                if (this.color.equals(colors[i])) {
+                    return colors[(i + 1) % colors.length];
+                }
+            }
+        }
+        return START_COLOR;
+    }
+
+
+    public int getDepth() {
+        if (this.parent == null) {
+            return 0;
+        } else {
+            return 1 + parent.getDepth();
+        }
+    }
+
+    /**
+     * This method sorts the given list in <b>descending<b> way.
+     * 
+     * @param nodes the list of {@link TreeMapNode} to sort.
+     */
+    public static void sort(List<TreeMapNode> nodes) {
+        Comparator<TreeMapNode> c = new Comparator<TreeMapNode>() {
+          @Override
+          public int compare(TreeMapNode o1, TreeMapNode o2) {
+              // inverting the result to descending sort the list
+              return -(Double.compare(o1.getWeight(), o2.getWeight()));
+          }
+      };
+      Collections.sort(nodes, c);
+    }
+}
--- /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/TreeMapPanel.java	Thu Jul 23 14:03:27 2015 +0200
@@ -0,0 +1,75 @@
+/*
+ * 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.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));
+    }
+
+    @Override
+    public void display(ObjectHistogram histogram) {
+        treeMap = new TreeMapComponent(histogram);
+        panel.add(treeMap);
+    }
+
+    @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/TreeProcessor.java	Thu Jul 23 14:03:27 2015 +0200
@@ -0,0 +1,111 @@
+/*
+ * 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.geom.Rectangle2D;
+import java.util.Objects;
+
+
+public class TreeProcessor {
+
+    /**
+     * Padding between the main component and its sub component.
+     */
+    public static final int X_PADDING = 15;
+    public static final int Y_PADDING = 20;
+
+    /**
+     * This method process recursively the tree nested in the node element
+     * passed as argument in the constructor calculating the children TreeMap 
+     * for each node also applying coloring.
+     * @return the updated tree, where nodes have additional information like
+     * {@link Rectangle2D>Float} instance and a color.
+     */
+    public static TreeMapNode processTreeMap(TreeMapNode tree, Rectangle2D.Double area) {
+        Objects.requireNonNull(tree);
+        Objects.requireNonNull(area);
+        tree.setRectangle(area);
+        if (tree.getColor() == null) {
+            tree.setColor(tree.START_COLOR);
+        }
+        
+        process(tree);
+        return tree;
+    }
+
+    /**
+     * This method is used to effectively process the whole tree structure. It
+     * uses a {@link SquarifiedTreeMap} object to calculate a TreeMap for each
+     * node who has children.
+     * @param node the subtree's root to process
+     */
+    private static void process(TreeMapNode node) {                                                                                                                            
+        
+        SquarifiedTreeMap algorithm = new SquarifiedTreeMap(getSubArea(node.getRectangle()), node.getChildren());
+        node.setChildren(algorithm.squarify());
+
+        Color c = node.getNextColor();
+        
+        for (TreeMapNode child : node.getChildren()) {
+            //children will have all the same color, which is the parent's next one
+            if (child.getColor() == null) {
+                child.setColor(c);
+            }
+            // if squarified rectangles have drawable sides then continue to 
+            // process, else don't process the subtree having as root a 
+            // non drawable rectangle.
+            if (child.isDrawable()) {
+                process(child);
+            } 
+        }
+    }
+
+    /**
+     * Calculate space and coordinates in which children's rectangle will be 
+     * drawn, from the main component.
+     * @return the rectangle representing the new available area.
+     */
+    private static Rectangle2D.Double getSubArea(Rectangle2D.Double area) {
+        Rectangle2D.Double subArea = new Rectangle2D.Double();
+        subArea.setRect(area);
+
+        subArea.width = Math.max(0, (subArea.width - 2 * X_PADDING));
+        subArea.height = Math.max(0, (subArea.height - 1.5 * Y_PADDING));
+        return subArea;
+    }  
+}
--- /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/ValueFormatter.java	Thu Jul 23 14:03:27 2015 +0200
@@ -0,0 +1,72 @@
+/*
+ * 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;
+
+public class ValueFormatter {
+    
+    private double value;
+    
+    public ValueFormatter(double val) {
+        this.value = val;
+    }
+    
+    /**
+     * This method returns the node value calculating it in bytes, KB or MB. 
+     * 
+     * i.e. if node's weight = 200 it returns: "200 bytes" <br>
+     * if weight = 20152: "20.15 KB"  <br>
+     * if weight = 2015248: "2.01 MB"  <br>
+     * 
+     * Note that float values are approximated to the second decimal digit.
+     */
+    public String format() {
+        int KB = 1000;
+        int MB = 1000000;
+        String unit = "Bytes";
+        
+        if (value >= KB && value < MB) {
+            value /= KB;
+            unit = "KBytes";
+        } else if (value >= MB) {
+            value /= MB;
+            unit = "MBytes";
+        }
+        // show 2 decimal digits 
+        String formattedValue = String.format("%.2f", value);
+        return formattedValue + " " + unit;
+    }
+}
--- a/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ActivatorTest.java	Tue Jul 07 12:23:45 2015 -0400
+++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ActivatorTest.java	Thu Jul 23 14:03:27 2015 +0200
@@ -45,15 +45,10 @@
 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.HeapTreeMapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
-import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.Activator;
-import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.SwingHeapDumpDetailsViewProvider;
-import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.SwingHeapHistogramViewProvider;
-import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.SwingHeapViewProvider;
-import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.SwingObjectDetailsViewProvider;
-import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.SwingObjectRootsViewProvider;
 
 public class ActivatorTest {
 
@@ -65,11 +60,12 @@
         assertTrue(ctx.isServiceRegistered(HeapViewProvider.class.getName(), SwingHeapViewProvider.class));
         assertTrue(ctx.isServiceRegistered(HeapDumpDetailsViewProvider.class.getName(), SwingHeapDumpDetailsViewProvider.class));
         assertTrue(ctx.isServiceRegistered(HeapHistogramViewProvider.class.getName(), SwingHeapHistogramViewProvider.class));
+        assertTrue(ctx.isServiceRegistered(HeapTreeMapViewProvider.class.getName(), SwingHeapTreeMapViewProvider.class));
         assertTrue(ctx.isServiceRegistered(ObjectDetailsViewProvider.class.getName(), SwingObjectDetailsViewProvider.class));
         assertTrue(ctx.isServiceRegistered(ObjectRootsViewProvider.class.getName(), SwingObjectRootsViewProvider.class));
         assertTrue(ctx.isServiceRegistered(HeapDumpListViewProvider.class.getName(), SwingHeapDumpListViewProvider.class));
 
-        assertEquals(6, ctx.getAllServices().size());
+        assertEquals(7, 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/HistogramConverterTest.java	Thu Jul 23 14:03:27 2015 +0200
@@ -0,0 +1,155 @@
+/*
+ * 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.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.vm.heap.analysis.common.HistogramRecord;
+import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram;
+import com.sun.tools.hat.internal.model.JavaClass;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+
+public class HistogramConverterTest {
+    
+    List<HistogramRecord> histrogramRecords;
+    ObjectHistogram histrogram;
+
+    @Before
+    public void setUp() throws Exception {
+        
+       
+        /*
+         *  This is the classes structure used for the test and built using histogram
+         * 
+         *                ________com_______                    java
+         *               /                  \                     |
+         *         __example1__           example2              lang
+         *        /            \             |                    |
+         *    package1      package2      package1              Object
+         *    /     \           |            |   
+         * Class1  Class2     Class3       Class4         
+         * 
+         * 
+         * 
+         * 
+         * Expected tree after conversion:
+         * 
+         *                           ________________________root_______________
+         *                          /                                           \
+         *                ________com_______                                java.lang.Object 
+         *               /                  \                               
+         *         __example1__           example2.package1.Class4        
+         *        /            \
+         *    package1      package2.Class3
+         *    /     \
+         *  Class1  Class2   
+         *      
+         */
+
+        final String[] classes = {
+                    "com.example1.package1.Class1", 
+                    "com.example1.package1.Class2",
+                    "com.example1.package2.Class3",
+                    "com.example2.package1.Class4",
+                    "java.lang.Object"
+                };
+        
+        histrogram = new ObjectHistogram();
+        
+        for (int i = 0; i < classes.length; i++) {
+            final String className = classes[i];
+            
+            histrogram.addThing(new JavaHeapObject() {
+                public int getSize() {
+                    return 0;
+                }
+                
+                public long getId() {
+                    return 0;
+                }
+                
+                public JavaClass getClazz() {
+                    return new JavaClass(className, 0, 0, 0, 0, null, null, 0);
+                }
+            });
+        }
+    }
+    
+    @Test
+    public final 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 java = tree.getChildren().get(1);
+        //java subtree collapses into java node
+        assertEquals(java.getLabel(), "java.lang.Object");
+        
+        TreeMapNode com = tree.getChildren().get(0);
+        assertEquals(com.getLabel(), "com"); 
+        
+        // com node has 2 children
+        assertTrue(com.getChildren().size() == 2);
+        
+        TreeMapNode example2 = com.getChildren().get(1); 
+        //example2 subtree has been collapsed in example2 node
+        assertEquals(example2.getLabel(), "example2.package1.Class4");
+        
+        TreeMapNode example1 = com.getChildren().get(0);
+        assertTrue(example1.getChildren().size() == 2);
+
+        TreeMapNode package2 = example1.getChildren().get(0);
+        //class3 node has been collapsed in package2 node
+        assertEquals(package2.getLabel(), "package2.Class3");
+        
+        TreeMapNode package1 = example1.getChildren().get(1);
+        assertTrue(package1.getChildren().size() == 2);
+        
+        assertEquals(package1.getChildren().get(0).getLabel(), "Class2");
+        assertEquals(package1.getChildren().get(1).getLabel(), "Class1");
+    }
+}
\ No newline at end of file
--- /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/SquarifiedTreeMapTest.java	Thu Jul 23 14:03:27 2015 +0200
@@ -0,0 +1,118 @@
+/*
+ * 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.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Using eclEmma tool has been proved that this test covers 100% 
+ * of {@link SquarifiedTreeMap} code and also 90% of {@link TreeMapBuilder} code.
+ */
+public class SquarifiedTreeMapTest {
+    
+    private SquarifiedTreeMap algorithm;
+    Rectangle2D.Double bounds;
+    List<TreeMapNode> list;
+
+    @Before
+    public void setUp() throws Exception {
+        bounds = new Rectangle2D.Double(0, 0, 10, 5);
+        list = new ArrayList<>();
+    }
+
+    @Test
+    public final void testSquarifiedTreeMap() {
+        //check every parameters combinations
+        boolean catched = false;
+        try {
+            algorithm = new SquarifiedTreeMap(null, null);
+        } catch(NullPointerException e) {
+            catched = true;
+        }
+        assertTrue(catched);
+        catched = false;
+        
+        try {
+            algorithm = new SquarifiedTreeMap(bounds, null);
+        } catch(NullPointerException e) {
+            catched = true;
+        }
+        assertTrue(catched);
+        catched = false;
+        
+        try {
+            algorithm = new SquarifiedTreeMap(null, list);
+        } catch(NullPointerException e) {
+            catched = true;
+        }
+        assertTrue(catched);
+    }
+    
+    @Test
+    public final void testSquarify() {
+        // test using an empty node list
+        algorithm = new SquarifiedTreeMap(bounds, new ArrayList<TreeMapNode>());
+        assertEquals(0, algorithm.squarify().size());
+        
+        // test using a correct list
+        int n = 10;
+        for (int i = 0; i < n; i++) {
+            list.add(new TreeMapNode(i+1));
+        }
+        // process the list
+        algorithm = new SquarifiedTreeMap(bounds, list);
+        list = algorithm.squarify();
+        
+        assertEquals(n, list.size());
+        
+        for (int i = 0; i < n; i++) {
+            // node has been processed
+            assertNotNull(list.get(i).getRectangle());
+        }
+        
+        assertEquals(list, algorithm.getSquarifiedNodes());
+    }
+}
--- /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/TreeMapComponentTest.java	Thu Jul 23 14:03:27 2015 +0200
@@ -0,0 +1,224 @@
+/*
+ * 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.assertEquals;
+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.BeforeClass;
+import org.junit.Test;
+
+
+public class TreeMapComponentTest {
+
+    private TreeMapComponent treeMap;
+    private static TreeMapNode tree;
+    private static TreeMapNode node1;
+    private static TreeMapNode node2;
+    private static Dimension dim;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        tree = new TreeMapNode(1);
+        node1 = new TreeMapNode(1);
+        node2 = new TreeMapNode(1);
+        tree.addChild(node1);
+        node1.addChild(node2);
+        dim = new Dimension(500, 500);
+    }
+
+
+    @Test
+    public final void testTreeMapComponent() throws InvocationTargetException, InterruptedException {
+
+        SwingUtilities.invokeAndWait(new Runnable() {
+
+            @Override
+            public void run() {
+
+                boolean catched = false;
+
+                try {
+                    treeMap = new TreeMapComponent(tree, dim);
+                    // pass
+                 } catch(NullPointerException e) {
+                    Assert.fail("Didn't expect exception.");
+                 }
+                try {
+                    treeMap = new TreeMapComponent(null, null);
+                } catch(NullPointerException e) {
+                    catched = true;
+                }
+                assertTrue(catched);
+                catched = false;
+
+                try {
+                    treeMap = new TreeMapComponent(tree, null);
+                } catch(NullPointerException e) {
+                    catched = true;
+                }
+                assertTrue(catched);
+                catched = false;
+
+                try {
+                    treeMap = new TreeMapComponent(null, dim);
+                } catch(NullPointerException e) {
+                    catched = true;
+                }
+                assertTrue(catched);
+            }
+        });
+    }
+
+    @Test
+    public final void testGetRoot() throws InvocationTargetException, InterruptedException {
+        SwingUtilities.invokeAndWait(new Runnable() {
+
+            @Override
+            public void run() {
+                treeMap = new TreeMapComponent(tree, dim);
+                assertEquals(tree, treeMap.getTreeMapRoot());
+            }
+        });
+    }
+
+    @Test
+    public final void testZoomIn() throws InvocationTargetException, InterruptedException {
+        SwingUtilities.invokeAndWait(new Runnable() {
+
+            @Override
+            public void run() {
+                TreeMapComponent treeMap = new TreeMapComponent(tree, dim);
+
+                treeMap.zoomIn(node1);
+                assertEquals(node1, treeMap.getTreeMapRoot());
+
+                treeMap.zoomIn(node2);
+                assertEquals(node2, treeMap.getTreeMapRoot());
+            }
+        });
+    }
+
+    @Test
+    public final void testZoomOut() throws InvocationTargetException, InterruptedException {
+        SwingUtilities.invokeAndWait(new Runnable() {
+
+            @Override
+            public void run() {
+                treeMap = new TreeMapComponent(tree, dim);
+
+                treeMap.zoomOut();
+                assertEquals(tree, treeMap.getTreeMapRoot());
+
+                treeMap.zoomIn(node1); //if zoom out root is tree
+                treeMap.zoomIn(node2); //if zoom out root is node1
+
+                treeMap.zoomOut();
+                assertEquals(node1, treeMap.getTreeMapRoot());
+
+                treeMap.zoomOut();
+                assertEquals(tree, treeMap.getTreeMapRoot());
+            }
+        });
+    }
+
+    @Test
+    public final void testZoomFull() throws InvocationTargetException, InterruptedException {
+        SwingUtilities.invokeAndWait(new Runnable() {
+
+            @Override
+            public void run() {
+                treeMap = new TreeMapComponent(tree, dim);
+
+                treeMap.zoomIn(node2);
+                treeMap.zoomFull();
+                assertEquals(tree, treeMap.getTreeMapRoot());
+
+            }
+        });
+    }
+
+    @Test
+    public final void testGetZoomCallsStack() throws InvocationTargetException, InterruptedException {
+        SwingUtilities.invokeAndWait(new Runnable() {
+
+            @Override
+            public void run() {
+                treeMap = new TreeMapComponent(tree, dim);
+
+                // the root is always in the stack
+                assertEquals(1, treeMap.getZoomCallsStack().size());
+
+                treeMap.zoomIn(tree);
+                // zooming on the same element nothing happen
+                assertEquals(1, treeMap.getZoomCallsStack().size());
+
+                treeMap.zoomIn(node1);
+                treeMap.zoomIn(node2);
+                treeMap.zoomFull();
+                assertEquals(tree, treeMap.getTreeMapRoot());
+            }
+        });
+    }
+
+
+    @Test
+    public final void testClearZoomCallsStack() throws InvocationTargetException, InterruptedException {
+        SwingUtilities.invokeAndWait(new Runnable() {
+
+            @Override
+            public void run() {
+                treeMap = new TreeMapComponent(tree, dim);
+
+                treeMap.clearZoomCallsStack();
+                assertEquals(1, treeMap.getZoomCallsStack().size());
+
+                treeMap.zoomIn(node1);
+                treeMap.zoomIn(node2);
+                treeMap.clearZoomCallsStack();
+                assertEquals(1, treeMap.getZoomCallsStack().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/TreeMapNodeTest.java	Thu Jul 23 14:03:27 2015 +0200
@@ -0,0 +1,284 @@
+/*
+ * 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.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.awt.Color;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class TreeMapNodeTest {
+
+    private TreeMapNode node;
+
+    @Before
+    public void setUp() {
+        node = new TreeMapNode(null, 1);
+    }
+
+    @Test
+    public final void testGetId() {
+        TreeMapNode node1 = new TreeMapNode(null, 1);
+        TreeMapNode node2 = new TreeMapNode(null, 1);
+        assertTrue(node1.getId() != node2.getId());
+        assertTrue(node1.getId() + 1 == node2.getId());
+    }
+
+    @Test
+    public final void testGetSetParent() {
+        TreeMapNode parent = new TreeMapNode(null, 1);
+        assertTrue(node.getParent() == null);
+        node.setParent(parent);
+        assertTrue(node.getParent() == parent);
+    }
+
+    @Test
+    public final void testGetSetLabel() {
+        TreeMapNode node = new TreeMapNode("MyLabel", 1);
+        assertTrue(node.getLabel().equals("MyLabel"));
+        node.setLabel("MyNewLabel");
+        assertTrue(node.getLabel().equals("MyNewLabel"));
+    }
+
+    @Test
+    public final void testGetSetChildren() {
+        assertTrue(node.getChildren().isEmpty());
+
+        TreeMapNode node = new TreeMapNode(null, 1);
+        List<TreeMapNode> children = new ArrayList<>();
+        children.add(node);
+
+        node.setChildren(children);
+        assertTrue(1 == node.getChildren().size());
+    }
+
+
+    @Test
+    public final void testGetAddInfo() {
+        node.addInfo("exampleKey", "exampleValue");
+        assertEquals("exampleValue", node.getInfo("exampleKey"));
+    }
+
+    @Test
+    public final void testAddChild() {
+        assertTrue(node.getChildren().size() == 0);
+        node.addChild(new TreeMapNode(null, 1));
+        assertTrue(node.getChildren().size() == 1);
+
+        node.addChild(null);
+        assertTrue(node.getChildren().size() == 1); // null has not been added
+    }
+
+    @Test
+    public final void testGetSetWeight() {
+        assertTrue(1 == node.getWeight());
+        node.setWeight(5);
+        assertTrue(5 == node.getWeight());
+    }
+
+    @Test
+    public final void testGetSetRectangle() {        
+        Rectangle2D.Double r = new Rectangle2D.Double(5, 5, 5, 5);
+        node.setRectangle(r);
+        assertEquals(r, node.getRectangle());
+
+        node.setRectangle(null);
+        boolean catched = false;
+        try {
+            node.getRectangle();
+        } catch(RuntimeException e) {
+            catched = true;
+        }
+        assertTrue(catched);
+    }
+
+
+    @Test
+    public final void testGetSetRealWeight() {
+        node = new TreeMapNode(null, 5);
+        assertTrue(node.getRealWeight() == 5);
+        node.setRealWeight(8);
+        assertTrue(node.getRealWeight() == 8);
+    }
+
+    @Test
+    public final void testAllowNonPositiveWeight() {
+        assertFalse(TreeMapNode.isAllowNonPositiveWeight());
+        node.setWeight(-5);
+        assertTrue(node.getWeight() == 1); // the real node weight
+        assertTrue(node.getRealWeight() == 1); 
+
+
+        TreeMapNode.setAllowNonPositiveWeight(true);
+        node.setWeight(-5);
+        assertTrue(node.getWeight() == -5);
+    }
+
+    @Test
+    public final void testIsDrawable() {
+        Rectangle2D.Double r = new Rectangle2D.Double(5, 5, 5, 5);
+        node.setRectangle(r);
+        assertTrue(node.isDrawable());
+
+        r.setRect(0,  0,  0.5f, 0.5f);
+        assertFalse(node.isDrawable());
+
+        r.setRect(0,  0,  5f, 0.5f);
+        assertFalse(node.isDrawable());
+
+        r.setRect(0,  0,  0.5f, 5f);
+        assertFalse(node.isDrawable());
+    }
+
+    @Test
+    public final void testGetSetColor() {
+        assertNull(node.getColor());
+        node.setColor(Color.black);
+        assertEquals(Color.black, node.getColor());
+    }
+
+    @Test
+    public final void testGetDepth() {
+        TreeMapNode depth1 = new TreeMapNode(null, 1);
+        TreeMapNode depth2 = new TreeMapNode(null, 1);
+
+        node.addChild(depth1);
+        depth1.addChild(depth2);
+
+        assertTrue(node.getDepth() == 0);
+        assertTrue(depth1.getDepth() == 1);
+        assertTrue(depth2.getDepth() == 2);
+    }
+
+    @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);
+        TreeMapNode n2 = new TreeMapNode(null, 4);
+        TreeMapNode n4 = new TreeMapNode(null, 2);
+        TreeMapNode n3 = new TreeMapNode(null, 3);
+        TreeMapNode n5 = new TreeMapNode(null, 0);
+        TreeMapNode n6 = new TreeMapNode(null, 7);
+        TreeMapNode n7 = new TreeMapNode(null, 1);
+        TreeMapNode n8 = new TreeMapNode(null, 9);
+
+        List<TreeMapNode> toSort = new ArrayList<>();
+        toSort.add(n3);
+        toSort.add(n2);
+        toSort.add(n4);
+        toSort.add(n1);
+        toSort.add(n5);
+        toSort.add(n6);
+        toSort.add(n7);
+        toSort.add(n8);
+
+        TreeMapNode.sort(toSort);
+
+        assertEquals(toSort.get(0), n8);
+        assertEquals(toSort.get(1), n6);
+        assertEquals(toSort.get(2), n1);
+        assertEquals(toSort.get(3), n2);
+        assertEquals(toSort.get(4), n3);
+        assertEquals(toSort.get(5), n4);
+        assertEquals(toSort.get(6), n7);
+        assertEquals(toSort.get(7), n5);
+    }
+
+    @Test
+    public final void testGetInfo() {
+        Map<String, String> map = node.getInfo();
+        assertNotNull(map);
+        assertEquals(0, map.keySet().size());
+    }
+
+    @Test
+    public final void testToString() {
+        assertNotNull(node.toString());
+    }
+    
+    
+    @Test
+    public final void testGetNextColor() {
+        assertNull(node.getColor());
+        assertTrue(node.getNextColor().equals(node.START_COLOR));
+        
+        Color start = node.START_COLOR;
+        node.setColor(start);
+
+        for (int i = 0; i < TreeMapNode.colors.length; i++) {
+            assertEquals(TreeMapNode.colors[i], node.getColor());
+            node.setColor(node.getNextColor());
+        }
+    }
+}
--- /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/TreeProcessorTest.java	Thu Jul 23 14:03:27 2015 +0200
@@ -0,0 +1,120 @@
+/*
+ * 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 static org.junit.Assert.fail;
+
+import java.awt.geom.Rectangle2D;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class TreeProcessorTest {
+
+    TreeMapNode node;
+    Rectangle2D.Double area;
+
+    @Before
+    public void setUp() throws Exception {
+        node = new TreeMapNode(1);
+        area = new Rectangle2D.Double(0, 0, 500, 500);
+    }
+
+    @Test
+    public final void testTreeProcessor() {
+        boolean catched = false;
+        // this test check all wrong combinations for constructor parameters
+        try {
+            TreeProcessor.processTreeMap(null, area);
+        } catch(NullPointerException e) {
+            catched = true;
+        }
+        assertTrue(catched);
+        catched = false;
+
+        try {
+            TreeProcessor.processTreeMap(node, null);
+        } catch(NullPointerException e) {
+            catched = true;
+        }
+        assertTrue(catched);
+        catched = false;
+
+        try {
+            TreeProcessor.processTreeMap(null, null);
+        } catch(NullPointerException e) {
+            catched = true;
+        }
+        assertTrue(catched);
+    }
+
+
+    @Test
+    public final void testProcessTreeMap() {
+        generateTree(node, 5, 5);
+        TreeProcessor.processTreeMap(node, area);
+
+        // the test will check if any drawable node in the tree has a rectangle and a 
+        // color, which means the processor function has processed the whole tree
+        traverse(node);        
+    }
+
+    private void traverse(TreeMapNode tree) {
+        if (tree.isDrawable() && (tree.getRectangle() == null || tree.getColor() == null)) {
+            fail("node " + tree.getId() + " not processed");
+        }
+        for (TreeMapNode child : tree.getChildren()) {
+            traverse(child);
+        }
+    }
+
+    private void generateTree(TreeMapNode root, int levels, int childrenNumber) {        
+        if (levels == 0) {
+            return;
+        } else {
+            for (int i = 0; i < childrenNumber; i++) {
+                root.addChild(new TreeMapNode(100));
+            }
+            for (TreeMapNode child : root.getChildren()) {
+                generateTree(child, levels-1, childrenNumber);
+            }
+        }
+    }
+}
--- /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/ValueFormatterTest.java	Thu Jul 23 14:03:27 2015 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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.assertEquals;
+
+import org.junit.Test;
+
+public class ValueFormatterTest {
+
+    private ValueFormatter formatter;
+
+    @Test
+    public final void getFormattedWeight() {
+        formatter = new ValueFormatter(2);
+        assertEquals("2.00 Bytes", formatter.format());
+
+        formatter = new ValueFormatter(2222);
+        assertEquals("2.22 KBytes", formatter.format());
+
+        formatter = new ValueFormatter(2222222);
+        assertEquals("2.22 MBytes", formatter.format());
+    }
+}
\ No newline at end of file