changeset 623:d771115988ea

Merge
author Roman Kennke <rkennke@redhat.com>
date Tue, 18 Sep 2012 21:17:02 +0200
parents 593c88ea5d0b (current diff) 210694fa00fe (diff)
children fca33da6c769
files client/core/src/main/java/com/redhat/thermostat/client/internal/AgentConfigurationSource.java client/core/src/main/java/com/redhat/thermostat/client/ui/AgentConfigurationController.java client/core/src/main/java/com/redhat/thermostat/client/ui/AgentConfigurationFrame.java client/core/src/main/java/com/redhat/thermostat/client/ui/AgentConfigurationModel.java client/core/src/main/java/com/redhat/thermostat/client/ui/AgentConfigurationView.java client/core/src/test/java/com/redhat/thermostat/client/ui/AgentConfigurationControllerTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/AgentConfigurationFrameTest.java client/swing-components/src/main/java/com/redhat/thermostat/charts/Chart.java client/swing-components/src/main/java/com/redhat/thermostat/swing/ToggleButton.java
diffstat 47 files changed, 2220 insertions(+), 1485 deletions(-) [+]
line wrap: on
line diff
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/AgentConfigurationSource.java	Tue Sep 18 21:13:17 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.internal;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class AgentConfigurationSource {
-
-    // FIXME fix this properly
-
-    public List<String> getKnownAgents() {
-        return Arrays.asList(new String[] { "Agent Smith", "Agent Jones", "Agent Brown" });
-    }
-
-    public Map<String, Boolean> getAgentBackends(String agentName) {
-        Map<String, Boolean> fake = new HashMap<>();
-        fake.put("Monitor New JVMs", true);
-        fake.put("Use up all my CPU Cycles", false);
-        return fake;
-    }
-
-    public void updateAgentConfig(String agentName, Map<String, Boolean> newBackendStatus) {
-        // TODO Auto-generated method stub
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/MainWindowControllerImpl.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/internal/MainWindowControllerImpl.java	Tue Sep 18 21:17:02 2012 +0200
@@ -57,9 +57,9 @@
 import com.redhat.thermostat.client.osgi.service.VmDecorator;
 import com.redhat.thermostat.client.osgi.service.VMContextAction;
 import com.redhat.thermostat.client.osgi.service.VmFilter;
-import com.redhat.thermostat.client.ui.AgentConfigurationController;
-import com.redhat.thermostat.client.ui.AgentConfigurationModel;
-import com.redhat.thermostat.client.ui.AgentConfigurationView;
+import com.redhat.thermostat.client.ui.AgentInformationDisplayController;
+import com.redhat.thermostat.client.ui.AgentInformationDisplayModel;
+import com.redhat.thermostat.client.ui.AgentInformationDisplayView;
 import com.redhat.thermostat.client.ui.ClientConfigurationController;
 import com.redhat.thermostat.client.ui.ClientConfigurationView;
 import com.redhat.thermostat.client.ui.HostInformationController;
@@ -403,10 +403,9 @@
     }
 
     private void showAgentConfiguration() {
-        AgentConfigurationSource agentPrefs = new AgentConfigurationSource();
-        AgentConfigurationModel model = new AgentConfigurationModel(agentPrefs);
-        AgentConfigurationView view = ApplicationContext.getInstance().getViewFactory().getView(AgentConfigurationView.class);
-        AgentConfigurationController controller = new AgentConfigurationController(model, view);
+        AgentInformationDisplayModel model = new AgentInformationDisplayModel();
+        AgentInformationDisplayView view = ApplicationContext.getInstance().getViewFactory().getView(AgentInformationDisplayView.class);
+        AgentInformationDisplayController controller = new AgentInformationDisplayController(model, view);
         controller.showView();
     }
 
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/SwingViewFactory.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/internal/SwingViewFactory.java	Tue Sep 18 21:17:02 2012 +0200
@@ -41,8 +41,8 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.client.ui.AgentConfigurationFrame;
-import com.redhat.thermostat.client.ui.AgentConfigurationView;
+import com.redhat.thermostat.client.ui.AgentInformationDisplayFrame;
+import com.redhat.thermostat.client.ui.AgentInformationDisplayView;
 import com.redhat.thermostat.client.ui.ClientConfigurationSwing;
 import com.redhat.thermostat.client.ui.ClientConfigurationView;
 import com.redhat.thermostat.client.ui.HostCpuPanel;
@@ -73,7 +73,7 @@
     private static final Logger logger = LoggingUtils.getLogger(SwingViewFactory.class);
 
     public SwingViewFactory() {
-        setViewClass(AgentConfigurationView.class, AgentConfigurationFrame.class);
+        setViewClass(AgentInformationDisplayView.class, AgentInformationDisplayFrame.class);
         setViewClass(ClientConfigurationView.class, ClientConfigurationSwing.class);
 
         setViewClass(SummaryView.class, SummaryPanel.class);
--- a/client/core/src/main/java/com/redhat/thermostat/client/locale/LocaleResources.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/locale/LocaleResources.java	Tue Sep 18 21:17:02 2012 +0200
@@ -36,6 +36,8 @@
 
 package com.redhat.thermostat.client.locale;
 
+import com.redhat.thermostat.client.ui.ValueField;
+
 public enum LocaleResources {
 
     MISSING_INFO,
@@ -57,9 +59,10 @@
     MENU_FILE,
     MENU_FILE_EXIT,
     MENU_EDIT,
-    MENU_EDIT_CONFIGURE_AGENT,
     MENU_EDIT_CONFIGURE_CLIENT,
     MENU_EDIT_ENABLE_HISTORY_MODE,
+    MENU_VIEW,
+    MENU_VIEW_AGENTS,
     MENU_HELP,
     MENU_HELP_ABOUT,
 
@@ -181,9 +184,21 @@
     VM_CLASSES_CHART_REAL_TIME_LABEL,
     VM_CLASSES_CHART_LOADED_CLASSES_LABEL,
 
-    CONFIGURE_AGENT_WINDOW_TITLE,
-    CONFIGURE_AGENT_AGENTS_LIST,
-    CONFIGURE_ENABLE_BACKENDS,
+    AGENT_INFO_WINDOW_TITLE,
+    AGENT_INFO_AGENTS_LIST,
+    AGENT_INFO_AGENT_SECTION_TITLE,
+    AGENT_INFO_AGENT_NAME_LABEL,
+    AGENT_INFO_AGENT_ID_LABEL,
+    AGENT_INFO_AGENT_COMMAND_ADDRESS_LABEL,
+    AGENT_INFO_AGENT_START_TIME_LABEL,
+    AGENT_INFO_AGENT_STOP_TIME_LABEL,
+    AGENT_INFO_AGENT_RUNNING,
+    AGENT_INFO_BACKENDS_SECTION_TITLE,
+    AGENT_INFO_BACKEND_NAME_COLUMN,
+    AGENT_INFO_BACKEND_STATUS_COLUMN,
+    AGENT_INFO_BACKEND_STATUS_ACTIVE,
+    AGENT_INFO_BACKEND_STATUS_INACTIVE,
+    AGENT_INFO_BACKEND_DESCRIPTION_LABEL,
 
     CLIENT_PREFS_WINDOW_TITLE,
     CLIENT_PREFS_CONNECTION,
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/AgentConfigurationController.java	Tue Sep 18 21:13:17 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.ui;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import com.redhat.thermostat.client.ui.AgentConfigurationView.ConfigurationAction;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-
-public class AgentConfigurationController implements ActionListener<ConfigurationAction> {
-
-    private final AgentConfigurationView view;
-    private final AgentConfigurationModel model;
-    private String agentName = null;
-
-    public AgentConfigurationController(AgentConfigurationModel model, AgentConfigurationView view) {
-        this.view = view;
-        this.model = model;
-
-        view.addActionListener(this);
-
-    }
-
-    public void showView() {
-        Collection<String> agents = model.getAgents();
-        agentName = null;
-        for (String agentName: agents) {
-            if (this.agentName == null) {
-                this.agentName = agentName;
-            }
-            view.addAgent(agentName);
-        }
-        view.showDialog();
-        updateViewFromModel();
-    }
-
-    public void hideView() {
-        view.hideDialog();
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent<ConfigurationAction> actionEvent) {
-        switch (actionEvent.getActionId()) {
-            case SWITCH_AGENT:
-                updateModelFromCurrentView();
-                String agentName = view.getSelectedAgent();
-                this.agentName = agentName;
-                updateViewFromModel();
-                break;
-            case CLOSE_ACCEPT:
-                updateModelFromCurrentView();
-                model.saveConfiguration();
-                /* fall through */
-            case CLOSE_CANCEL:
-                hideView();
-                break;
-            default:
-                throw new IllegalArgumentException("unknown event");
-        }
-    }
-
-    private void updateModelFromCurrentView() {
-        Map<String, Boolean> map = view.getBackendStatus();
-        for (Entry<String, Boolean> entry: map.entrySet()) {
-            model.setBackendEnabled(agentName, entry.getKey(), entry.getValue());
-        }
-
-    }
-
-    private void updateViewFromModel() {
-        Map<String, Boolean> map = new HashMap<>();
-        for (String backendName: model.getBackends(agentName)) {
-            map.put(backendName, model.getAgentBackendEnabled(agentName, backendName));
-        }
-        view.setBackendStatus(map);
-
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/AgentConfigurationFrame.java	Tue Sep 18 21:13:17 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,321 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.ui;
-
-import static com.redhat.thermostat.client.locale.Translate.localize;
-
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import javax.swing.Box;
-import javax.swing.DefaultListModel;
-import javax.swing.GroupLayout;
-import javax.swing.GroupLayout.Alignment;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.LayoutStyle.ComponentPlacement;
-import javax.swing.SwingUtilities;
-
-import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import javax.swing.JScrollPane;
-import javax.swing.JList;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-
-public class AgentConfigurationFrame extends JFrame implements AgentConfigurationView {
-
-    private static final long serialVersionUID = -6049272471909474886L;
-
-    private final CopyOnWriteArrayList<ActionListener<ConfigurationAction>> listeners = new CopyOnWriteArrayList<>();
-
-    private final Map<String, JCheckBox> backends = Collections.synchronizedMap(new HashMap<String, JCheckBox>());
-
-    private final JPanel availableBackendsPanel;
-    private final GridBagConstraints availableBackendsPanelContstraints = new GridBagConstraints();
-
-    private final ConfigurationCompleteListener configurationComplete;
-    private final AgentChangedListener agentChanged;
-    private final WindowClosingListener windowListener;
-
-    private final JButton okayButton;
-    private final JButton cancelButton;
-
-    private final JList<String> agentList;
-    private final DefaultListModel<String> listModel;
-
-
-    public AgentConfigurationFrame() {
-        assertInEDT();
-
-        configurationComplete = new ConfigurationCompleteListener();
-        agentChanged = new AgentChangedListener();
-        windowListener = new WindowClosingListener();
-
-        setTitle(localize(LocaleResources.CONFIGURE_AGENT_WINDOW_TITLE));
-        addWindowListener(windowListener);
-
-        JLabel lblEnabledisableBackends = new JLabel(localize(LocaleResources.CONFIGURE_ENABLE_BACKENDS));
-
-        availableBackendsPanel = new JPanel();
-
-        okayButton = new JButton(localize(LocaleResources.BUTTON_OK));
-        okayButton.addActionListener(configurationComplete);
-
-        cancelButton = new JButton(localize(LocaleResources.BUTTON_CANCEL));
-        cancelButton.addActionListener(configurationComplete);
-
-        JScrollPane scrollPane = new JScrollPane();
-
-        JLabel lblAgents = new JLabel(localize(LocaleResources.CONFIGURE_AGENT_AGENTS_LIST));
-
-        GroupLayout groupLayout = new GroupLayout(getContentPane());
-        groupLayout.setHorizontalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                        .addGroup(groupLayout.createSequentialGroup()
-                            .addComponent(scrollPane, GroupLayout.PREFERRED_SIZE, 127, GroupLayout.PREFERRED_SIZE)
-                            .addGap(0)
-                            .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                                .addGroup(Alignment.TRAILING, groupLayout.createSequentialGroup()
-                                    .addComponent(cancelButton)
-                                    .addPreferredGap(ComponentPlacement.RELATED)
-                                    .addComponent(okayButton))
-                                .addGroup(groupLayout.createSequentialGroup()
-                                    .addGap(12)
-                                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                                        .addGroup(groupLayout.createSequentialGroup()
-                                            .addGap(12)
-                                            .addComponent(availableBackendsPanel, GroupLayout.DEFAULT_SIZE, 540, Short.MAX_VALUE))
-                                        .addComponent(lblEnabledisableBackends)))))
-                        .addComponent(lblAgents))
-                    .addContainerGap())
-        );
-        groupLayout.setVerticalGroup(
-            groupLayout.createParallelGroup(Alignment.TRAILING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addGap(6)
-                    .addComponent(lblAgents)
-                    .addPreferredGap(ComponentPlacement.UNRELATED)
-                    .addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
-                        .addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 413, Short.MAX_VALUE)
-                        .addGroup(groupLayout.createSequentialGroup()
-                            .addComponent(lblEnabledisableBackends)
-                            .addGap(2)
-                            .addComponent(availableBackendsPanel, GroupLayout.DEFAULT_SIZE, 365, Short.MAX_VALUE)
-                            .addPreferredGap(ComponentPlacement.RELATED)
-                            .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
-                                .addComponent(okayButton)
-                                .addComponent(cancelButton))))
-                    .addContainerGap())
-        );
-
-        listModel = new DefaultListModel<String>();
-        agentList = new JList<String>(listModel);
-        agentList.setName("agentList");
-        agentList.addListSelectionListener(agentChanged);
-        scrollPane.setViewportView(agentList);
-
-        availableBackendsPanel.setLayout(new GridBagLayout());
-        getContentPane().setLayout(groupLayout);
-
-    }
-
-    private void resetConstraints() {
-        availableBackendsPanelContstraints.gridwidth = 1;
-        availableBackendsPanelContstraints.gridy = 0;
-        availableBackendsPanelContstraints.gridx = 0;
-        availableBackendsPanelContstraints.weightx = 0;
-        availableBackendsPanelContstraints.weighty = 0;
-        availableBackendsPanelContstraints.anchor = GridBagConstraints.LINE_START;
-        availableBackendsPanelContstraints.fill = GridBagConstraints.BOTH;
-    }
-
-
-    @Override
-    public void addActionListener(ActionListener<ConfigurationAction> listener) {
-        listeners.add(listener);
-    }
-
-    @Override
-    public void removeActionListener(ActionListener<ConfigurationAction> listener) {
-        listeners.remove(listener);
-    }
-
-    @Override
-    public void addAgent(final String agentName) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                listModel.addElement(agentName);
-            }
-        });
-    }
-
-    @Override
-    public String getSelectedAgent() {
-        assertInEDT();
-        return agentList.getSelectedValue();
-    }
-
-    @Override
-    public void clearAllAgents() {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                listModel.clear();
-            }
-        });
-    }
-
-
-    @Override
-    public void setBackendStatus(final Map<String, Boolean> backendStatus) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                backends.clear();
-                availableBackendsPanel.removeAll();
-                resetConstraints();
-
-                for (Entry<String, Boolean> entry: backendStatus.entrySet()) {
-                    String backendName = entry.getKey();
-                    boolean checked = entry.getValue();
-                    JCheckBox checkBox = new JCheckBox(backendName);
-                    checkBox.setSelected(checked);
-                    checkBox.setActionCommand(backendName);
-                    backends.put(backendName, checkBox);
-                    availableBackendsPanel.add(checkBox, availableBackendsPanelContstraints);
-                    availableBackendsPanelContstraints.gridy++;
-                }
-                availableBackendsPanelContstraints.weighty = 1.0;
-                availableBackendsPanelContstraints.weightx = 1.0;
-                availableBackendsPanelContstraints.fill = GridBagConstraints.BOTH;
-                availableBackendsPanel.add(Box.createGlue(), availableBackendsPanelContstraints);
-                AgentConfigurationFrame.this.revalidate();
-            }
-        });
-    }
-
-    @Override
-    public Map<String, Boolean> getBackendStatus() {
-        assertInEDT();
-
-        Map<String,Boolean> latestUserSpecified = new HashMap<>();
-        for (Entry<String, JCheckBox> entry: backends.entrySet()) {
-            latestUserSpecified.put(entry.getKey(), entry.getValue().isSelected());
-        }
-        return latestUserSpecified;
-    }
-
-    @Override
-    public void showDialog() {
-        assertInEDT();
-
-        pack();
-        setVisible(true);
-
-        agentList.setSelectedIndex(0);
-    }
-
-    @Override
-    public void hideDialog() {
-        assertInEDT();
-
-        setVisible(false);
-        dispose();
-    }
-
-    private void fireAction(ActionEvent<ConfigurationAction> actionEvent) {
-        for (ActionListener<ConfigurationAction> l: listeners) {
-            l.actionPerformed(actionEvent);
-        }
-    }
-
-    private static void assertInEDT() {
-        if (!SwingUtilities.isEventDispatchThread()) {
-            throw new IllegalStateException("must be called from within the swing EDT");
-        }
-    }
-
-    class ConfigurationCompleteListener implements java.awt.event.ActionListener {
-        @Override
-        public void actionPerformed(java.awt.event.ActionEvent e) {
-            Object source = e.getSource();
-            if (source == okayButton) {
-                fireAction(new ActionEvent<>(AgentConfigurationFrame.this, ConfigurationAction.CLOSE_ACCEPT));
-            } else if (source == cancelButton) {
-                fireAction(new ActionEvent<>(AgentConfigurationFrame.this, ConfigurationAction.CLOSE_CANCEL));
-            }
-        }
-    }
-
-    class WindowClosingListener extends WindowAdapter {
-        @Override
-        public void windowClosing(WindowEvent e) {
-            fireAction(new ActionEvent<>(AgentConfigurationFrame.this, ConfigurationAction.CLOSE_CANCEL));
-        }
-    }
-
-    class AgentChangedListener implements ListSelectionListener {
-        @Override
-        public void valueChanged(ListSelectionEvent e) {
-            if (e.getSource() == agentList) {
-                if (e.getValueIsAdjusting()) {
-                    return;
-                }
-                fireAction(new ActionEvent<>(AgentConfigurationFrame.this, ConfigurationAction.SWITCH_AGENT));
-            } else {
-                throw new IllegalStateException("unknown trigger");
-            }
-        }
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/AgentConfigurationModel.java	Tue Sep 18 21:13:17 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.ui;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import com.redhat.thermostat.client.internal.AgentConfigurationSource;
-
-/**
- * This model sits between the current view and the remote model, and allows
- * us to make changes and later throw them away.
- */
-public class AgentConfigurationModel {
-
-    private final AgentConfigurationSource remoteConfiguration;
-
-    private final List<String> knownAgents;
-    private Map<String, Map<String, Boolean>> enabledBackends;
-
-    public AgentConfigurationModel(AgentConfigurationSource configSource) {
-        this.remoteConfiguration = configSource;
-
-        knownAgents = new ArrayList<>(remoteConfiguration.getKnownAgents());
-        enabledBackends = new HashMap<>();
-        for (String agent: knownAgents) {
-            enabledBackends.put(agent, new HashMap<String, Boolean>(remoteConfiguration.getAgentBackends(agent)));
-        }
-    }
-
-    public Collection<String> getAgents() {
-        return Collections.unmodifiableList(knownAgents);
-    }
-
-    public Collection<String> getBackends(String agentName) {
-        return Collections.unmodifiableSet(enabledBackends.get(agentName).keySet());
-    }
-
-    public void setBackendEnabled(String agentName, String backendName, boolean enabled) {
-        enabledBackends.get(agentName).put(backendName, enabled);
-    }
-
-    public boolean getAgentBackendEnabled(String agentName, String backendName) {
-        return enabledBackends.get(agentName).get(backendName);
-    }
-
-    public void saveConfiguration() {
-        for (Entry<String, Map<String, Boolean>> entry: enabledBackends.entrySet()) {
-            remoteConfiguration.updateAgentConfig(entry.getKey(), entry.getValue());
-        }
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/AgentConfigurationView.java	Tue Sep 18 21:13:17 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.ui;
-
-import java.util.Map;
-
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.View;
-
-public interface AgentConfigurationView extends View {
-
-    enum ConfigurationAction {
-        SWITCH_AGENT,
-        CLOSE_ACCEPT,
-        CLOSE_CANCEL,
-    }
-
-    void showDialog();
-
-    void hideDialog();
-
-    void addActionListener(ActionListener<ConfigurationAction> listener);
-
-    void removeActionListener(ActionListener<ConfigurationAction> listener);
-
-    void addAgent(String agentName);
-
-    String getSelectedAgent();
-
-    void clearAllAgents();
-
-    void setBackendStatus(Map<String,Boolean> agentConfiguration);
-
-    Map<String,Boolean> getBackendStatus();
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/AgentInformationDisplayController.java	Tue Sep 18 21:17:02 2012 +0200
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.ui;
+
+import static com.redhat.thermostat.client.locale.Translate.localize;
+
+import java.text.DateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.ui.AgentInformationDisplayView.ConfigurationAction;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.model.AgentInformation;
+import com.redhat.thermostat.common.model.BackendInformation;
+
+public class AgentInformationDisplayController implements ActionListener<ConfigurationAction> {
+
+    private final AgentInformationDisplayView view;
+    private final AgentInformationDisplayModel model;
+
+    private final DateFormat dateTimeFormat;
+
+    public AgentInformationDisplayController(AgentInformationDisplayModel model, AgentInformationDisplayView view) {
+        this.view = view;
+        this.model = model;
+
+        view.addConfigurationListener(this);
+
+        dateTimeFormat = DateFormat.getDateTimeInstance();
+    }
+
+    public void showView() {
+        Collection<AgentInformation> agents = model.getAgents();
+        String agentId = null;
+        for (AgentInformation agentInfo : agents) {
+            String agentName = agentInfo.getAgentId();
+            if (agentId == null) {
+                agentId = agentInfo.getAgentId();
+            }
+            view.addAgent(agentName);
+        }
+        view.showDialog();
+        updateViewFromModel(agentId);
+    }
+
+    public void hideView() {
+        view.hideDialog();
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent<ConfigurationAction> actionEvent) {
+        String agentId = view.getSelectedAgent();
+        switch (actionEvent.getActionId()) {
+        case SWITCH_AGENT:
+            updateViewFromModel(agentId);
+            break;
+        case SHOW_BACKEND_DESCRIPTION:
+            String backendName = (String) actionEvent.getPayload();
+            view.setSelectedAgentBackendDescription(getBackendDescription(agentId, backendName));
+            break;
+        case CLOSE:
+            hideView();
+            break;
+        default:
+            throw new IllegalArgumentException("unknown event");
+        }
+    }
+
+    private String getBackendDescription(String agentId, String backendName) {
+        return getBackendInformation(agentId, backendName).getDescription();
+    }
+
+    private BackendInformation getBackendInformation(String agentId, String backendName) {
+        Collection<BackendInformation> backendInfos = model.getBackends(agentId);
+        for (BackendInformation backendInfo : backendInfos) {
+            if (backendInfo.getName().equals(backendName)) {
+                return backendInfo;
+            }
+        }
+        return null;
+    }
+
+    private void updateViewFromModel(String agentId) {
+        AgentInformation agentInfo = model.getAgentInfo(agentId);
+        view.setSelectedAgentName(agentInfo.getAgentId());
+        view.setSelectedAgentId(agentInfo.getAgentId());
+        view.setSelectedAgentCommandAddress(agentInfo.getConfigListenAddress());
+        long startTime = agentInfo.getStartTime();
+        view.setSelectedAgentStartTime(dateTimeFormat.format(new Date(startTime)));
+        long stopTime = agentInfo.getStopTime();
+        if (stopTime >= startTime) {
+            view.setSelectedAgentStopTime(dateTimeFormat.format(new Date(stopTime)));
+        } else {
+            view.setSelectedAgentStopTime(localize(LocaleResources.AGENT_INFO_AGENT_RUNNING));
+        }
+
+        Map<String, String> map = new HashMap<>();
+        for (BackendInformation backendInfo : model.getBackends(agentId)) {
+            String status = backendInfo.isActive() ?
+                    localize(LocaleResources.AGENT_INFO_BACKEND_STATUS_ACTIVE) : localize(LocaleResources.AGENT_INFO_BACKEND_STATUS_INACTIVE);
+            map.put(backendInfo.getName(), status);
+        }
+        view.setSelectedAgentBackendStatus(map);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/AgentInformationDisplayFrame.java	Tue Sep 18 21:17:02 2012 +0200
@@ -0,0 +1,458 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.ui;
+
+import static com.redhat.thermostat.client.locale.Translate.localize;
+
+import java.awt.BorderLayout;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.swing.DefaultListModel;
+import javax.swing.GroupLayout;
+import javax.swing.GroupLayout.Alignment;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTable;
+import javax.swing.LayoutStyle.ComponentPlacement;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.DefaultTableModel;
+
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+
+public class AgentInformationDisplayFrame extends AgentInformationDisplayView {
+
+    private static final String[] BACKEND_TABLE_COLUMN_NAMES = new String[] {
+        localize(LocaleResources.AGENT_INFO_BACKEND_NAME_COLUMN),
+        localize(LocaleResources.AGENT_INFO_BACKEND_STATUS_COLUMN),
+    };
+
+    private final CopyOnWriteArrayList<ActionListener<ConfigurationAction>> listeners = new CopyOnWriteArrayList<>();
+
+    private final JFrame frame;
+
+    private final ConfigurationCompleteListener configurationComplete;
+    private final AgentChangedListener agentChanged;
+    private final WindowClosingListener windowListener;
+
+    private final JButton closeButton;
+
+    private final JList<String> agentList;
+    private final DefaultListModel<String> listModel;
+
+    private final ValueField currentAgentName;
+    private final ValueField currentAgentId;
+    private final ValueField currentAgentCommandAddress;
+    private final ValueField currentAgentStartTime;
+    private final ValueField currentAgentStopTime;
+
+    private final JTable backendsTable;
+    private final DefaultTableModel backendsTableModel;
+    private final ValueField backendDescription;
+
+    public AgentInformationDisplayFrame() {
+        assertInEDT();
+
+        configurationComplete = new ConfigurationCompleteListener();
+        agentChanged = new AgentChangedListener();
+        windowListener = new WindowClosingListener();
+
+        frame = new JFrame();
+        frame.setTitle(localize(LocaleResources.AGENT_INFO_WINDOW_TITLE));
+        frame.addWindowListener(windowListener);
+
+        closeButton = new JButton(localize(LocaleResources.BUTTON_CLOSE));
+        closeButton.addActionListener(configurationComplete);
+        closeButton.setName("close");
+
+        JSplitPane splitPane = new JSplitPane();
+        splitPane.setResizeWeight(0.35);
+
+        GroupLayout mainLayout = new GroupLayout(frame.getContentPane());
+        mainLayout.setHorizontalGroup(
+            mainLayout.createParallelGroup(Alignment.TRAILING)
+                .addGroup(mainLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addGroup(mainLayout.createParallelGroup(Alignment.TRAILING)
+                        .addComponent(splitPane, GroupLayout.DEFAULT_SIZE, 664, Short.MAX_VALUE)
+                        .addComponent(closeButton))
+                    .addContainerGap()));
+
+        mainLayout.setVerticalGroup(
+            mainLayout.createParallelGroup(Alignment.TRAILING)
+                .addGroup(mainLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addComponent(splitPane, GroupLayout.DEFAULT_SIZE, 472, Short.MAX_VALUE)
+                    .addPreferredGap(ComponentPlacement.UNRELATED)
+                    .addComponent(closeButton)
+                    .addContainerGap()));
+
+        JPanel agentListPanel = new JPanel();
+        splitPane.setLeftComponent(agentListPanel);
+
+        JLabel agentLabel = new JLabel(localize(LocaleResources.AGENT_INFO_AGENTS_LIST));
+
+        JScrollPane scrollPane = new JScrollPane();
+
+        listModel = new DefaultListModel<String>();
+        agentList = new JList<String>(listModel);
+        agentList.setName("agentList");
+        agentList.addListSelectionListener(agentChanged);
+        agentListPanel.setLayout(new BorderLayout());
+
+        scrollPane.setViewportView(agentList);
+        agentListPanel.add(scrollPane);
+        agentListPanel.add(agentLabel, BorderLayout.NORTH);
+
+        JPanel agentConfigurationPanel = new JPanel();
+        splitPane.setRightComponent(agentConfigurationPanel);
+
+        SectionHeader agentSectionTitle = new SectionHeader(localize(LocaleResources.AGENT_INFO_AGENT_SECTION_TITLE));
+
+        LabelField agentNameLabel = new LabelField(localize(LocaleResources.AGENT_INFO_AGENT_NAME_LABEL));
+        LabelField agentIdLabel = new LabelField(localize(LocaleResources.AGENT_INFO_AGENT_ID_LABEL));
+        LabelField agentConfigurationAddressLabel = new LabelField(localize(LocaleResources.AGENT_INFO_AGENT_COMMAND_ADDRESS_LABEL));
+        LabelField agentStartTimeLabel = new LabelField(localize(LocaleResources.AGENT_INFO_AGENT_START_TIME_LABEL));
+        LabelField agentStopTimeLabel = new LabelField(localize(LocaleResources.AGENT_INFO_AGENT_STOP_TIME_LABEL));
+
+        currentAgentName = new ValueField("${AGENT_NAME}");
+        currentAgentName.setName("agentName");
+        currentAgentId = new ValueField("${AGENT_ID}");
+        currentAgentId.setName("agentId");
+        currentAgentCommandAddress = new ValueField("${AGENT_COMMAND_ADDRESS}");
+        currentAgentCommandAddress.setName("commandAddress");
+        currentAgentStartTime = new ValueField("${START_TIME}");
+        currentAgentStartTime.setName("startTime");
+        currentAgentStopTime = new ValueField("${STOP_TIME}");
+        currentAgentStopTime.setName("stopTime");
+
+        SectionHeader backendSectionTitle = new SectionHeader(localize(LocaleResources.AGENT_INFO_BACKENDS_SECTION_TITLE));
+
+        backendsTableModel = new DefaultTableModel();
+        backendsTableModel.setColumnIdentifiers(BACKEND_TABLE_COLUMN_NAMES);
+
+        backendsTable = new JTable(backendsTableModel);
+        backendsTable.setName("backends");
+        backendsTable.setCellSelectionEnabled(false);
+        backendsTable.setColumnSelectionAllowed(false);
+        backendsTable.setRowSelectionAllowed(true);
+        backendsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        backendsTable.getSelectionModel().addListSelectionListener(new BackendSelectionListener());
+
+        JScrollPane backendsTableScollPane = new JScrollPane(backendsTable);
+
+        JLabel backendDescriptionLabel = new JLabel(localize(LocaleResources.AGENT_INFO_BACKEND_DESCRIPTION_LABEL));
+        backendDescription = new ValueField("${DESCRIPTION}");
+        backendDescription.setName("backendDescription");
+
+        GroupLayout agentConfigurationPanelLayout = new GroupLayout(agentConfigurationPanel);
+        agentConfigurationPanelLayout.setHorizontalGroup(
+            agentConfigurationPanelLayout.createParallelGroup()
+                .addComponent(agentSectionTitle, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addGroup(agentConfigurationPanelLayout.createSequentialGroup()
+                    .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.LEADING, true)
+                        .addComponent(agentNameLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                        .addComponent(agentIdLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                        .addComponent(agentConfigurationAddressLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                        .addComponent(agentStartTimeLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                        .addComponent(agentStopTimeLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                    .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.LEADING, true)
+                        .addComponent(currentAgentName, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
+                        .addComponent(currentAgentId, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
+                        .addComponent(currentAgentCommandAddress, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
+                        .addComponent(currentAgentStartTime, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
+                        .addComponent(currentAgentStopTime, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)))
+                .addComponent(backendSectionTitle, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
+                .addComponent(backendsTableScollPane, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
+                .addComponent(backendDescriptionLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addComponent(backendDescription, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE));
+
+        agentConfigurationPanelLayout.setVerticalGroup(
+            agentConfigurationPanelLayout.createSequentialGroup()
+                .addComponent(agentSectionTitle)
+                .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.BASELINE, false)
+                    .addComponent(agentNameLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                    .addComponent(currentAgentName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.BASELINE, false)
+                    .addComponent(agentIdLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                    .addComponent(currentAgentId, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.BASELINE, false)
+                    .addComponent(agentConfigurationAddressLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                    .addComponent(currentAgentCommandAddress, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.BASELINE, false)
+                    .addComponent(agentStartTimeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                    .addComponent(currentAgentStartTime, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.BASELINE, false)
+                    .addComponent(agentStopTimeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                    .addComponent(currentAgentStopTime, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                .addComponent(backendSectionTitle)
+                .addComponent(backendsTableScollPane)
+                .addComponent(backendDescriptionLabel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE)
+                .addComponent(backendDescription, 30, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE));
+
+        agentConfigurationPanelLayout.setAutoCreateGaps(true);
+        agentConfigurationPanelLayout.setAutoCreateContainerGaps(true);
+        agentConfigurationPanel.setLayout(agentConfigurationPanelLayout);
+
+        frame.getContentPane().setLayout(mainLayout);
+
+    }
+
+    @Override
+    public void addConfigurationListener(ActionListener<ConfigurationAction> listener) {
+        listeners.add(listener);
+    }
+
+    @Override
+    public void removeConfigurationListener(ActionListener<ConfigurationAction> listener) {
+        listeners.remove(listener);
+    }
+
+    @Override
+    public void addAgent(final String agentName) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                listModel.addElement(agentName);
+                if (agentList.getSelectedIndex() == -1) {
+                    agentList.setSelectedIndex(0);
+                }
+            }
+        });
+    }
+
+    @Override
+    public String getSelectedAgent() {
+        assertInEDT();
+        return agentList.getSelectedValue();
+    }
+
+    @Override
+    public void clearAllAgents() {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                listModel.clear();
+            }
+        });
+    }
+
+    @Override
+    public void setSelectedAgentName(final String agentName) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                currentAgentName.setText(agentName);
+            }
+        });
+    }
+
+    @Override
+    public void setSelectedAgentId(final String agentId) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                currentAgentId.setText(agentId);
+            }
+        });
+    }
+
+    @Override
+    public void setSelectedAgentCommandAddress(final String address) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                currentAgentCommandAddress.setText(address);
+            }
+        });
+    }
+
+    @Override
+    public void setSelectedAgentStartTime(final String startTime) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                currentAgentStartTime.setText(startTime);
+            }
+        });
+    }
+
+    @Override
+    public void setSelectedAgentStopTime(final String stopTime) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                currentAgentStopTime.setText(stopTime);
+            }
+        });
+    }
+
+    @Override
+    public void setSelectedAgentBackendStatus(final Map<String, String> backendStatus) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                int i = 0;
+                for (Entry<String, String> entry : backendStatus.entrySet()) {
+                    String backendName = entry.getKey();
+                    String status = entry.getValue();
+                    int rowCount = backendsTableModel.getRowCount();
+                    if (i >= rowCount) {
+                        Object[] rowData = new String[] { backendName, status };
+                        backendsTableModel.insertRow(i, rowData);
+                    } else {
+                        backendsTableModel.setValueAt(backendName, i, 0);
+                        backendsTableModel.setValueAt(status, i, 1);
+                    }
+                    i++;
+                }
+
+                if (backendsTable.getRowCount() > 0 && backendsTable.getSelectedRow() == -1) {
+                    backendsTable.setRowSelectionInterval(0, 0);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void setSelectedAgentBackendDescription(final String description) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                backendDescription.setText(description);
+            }
+        });
+    }
+
+    @Override
+    public void showDialog() {
+        assertInEDT();
+
+        frame.pack();
+        frame.setVisible(true);
+
+        agentList.setSelectedIndex(0);
+    }
+
+    @Override
+    public void hideDialog() {
+        assertInEDT();
+
+        frame.setVisible(false);
+        frame.dispose();
+    }
+
+    /** This is for tests only */
+    JFrame getFrame() {
+        return frame;
+    }
+
+    private void fireAction(ActionEvent<ConfigurationAction> actionEvent) {
+        for (ActionListener<ConfigurationAction> l : listeners) {
+            l.actionPerformed(actionEvent);
+        }
+    }
+
+    private static void assertInEDT() {
+        if (!SwingUtilities.isEventDispatchThread()) {
+            throw new IllegalStateException("must be called from within the swing EDT");
+        }
+    }
+
+    private class ConfigurationCompleteListener implements java.awt.event.ActionListener {
+        @Override
+        public void actionPerformed(java.awt.event.ActionEvent e) {
+            Object source = e.getSource();
+            if (source == closeButton) {
+                fireAction(new ActionEvent<>(AgentInformationDisplayFrame.this, ConfigurationAction.CLOSE));
+            }
+        }
+    }
+
+    private class WindowClosingListener extends WindowAdapter {
+        @Override
+        public void windowClosing(WindowEvent e) {
+            fireAction(new ActionEvent<>(AgentInformationDisplayFrame.this, ConfigurationAction.CLOSE));
+        }
+    }
+
+    private class AgentChangedListener implements ListSelectionListener {
+        @Override
+        public void valueChanged(ListSelectionEvent e) {
+            if (e.getSource() == agentList) {
+                if (e.getValueIsAdjusting()) {
+                    return;
+                }
+                fireAction(new ActionEvent<>(AgentInformationDisplayFrame.this, ConfigurationAction.SWITCH_AGENT));
+            } else {
+                throw new IllegalStateException("unknown trigger");
+            }
+        }
+    }
+
+    private class BackendSelectionListener implements ListSelectionListener {
+
+        @Override
+        public void valueChanged(ListSelectionEvent e) {
+            if (e.getValueIsAdjusting()) {
+                return;
+            }
+
+            int rowIndex = e.getFirstIndex();
+            String backendName = (String) backendsTableModel.getValueAt(rowIndex, 0);
+            ActionEvent<ConfigurationAction> event = new ActionEvent<>(AgentInformationDisplayFrame.this,
+                    ConfigurationAction.SHOW_BACKEND_DESCRIPTION);
+            event.setPayload(backendName);
+            fireAction(event);
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/AgentInformationDisplayModel.java	Tue Sep 18 21:17:02 2012 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.ui;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
+import com.redhat.thermostat.common.dao.BackendInfoDAO;
+import com.redhat.thermostat.common.dao.DAOFactory;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.model.AgentInformation;
+import com.redhat.thermostat.common.model.BackendInformation;
+
+/**
+ * This model sits between the current view and the remote model, and maintains
+ * a state of the agents that it knows about.
+ */
+public class AgentInformationDisplayModel {
+
+    private final AgentInfoDAO agentInfoDao;
+    private final BackendInfoDAO backendInfoDao;
+
+    private final List<AgentInformation> agents;
+    private final Map<String, List<BackendInformation>> backends;
+
+    public AgentInformationDisplayModel() {
+        ApplicationContext appContext = ApplicationContext.getInstance();
+        DAOFactory daoFactory = appContext.getDAOFactory();
+        agentInfoDao = daoFactory.getAgentInfoDAO();
+        backendInfoDao = daoFactory.getBackendInfoDAO();
+
+        agents = new ArrayList<>();
+        backends = new HashMap<>();
+
+        refresh();
+    }
+
+    public Collection<AgentInformation> getAgents() {
+        return agents;
+    }
+
+    public AgentInformation getAgentInfo(String agentId) {
+        for (AgentInformation agent : agents) {
+            if (agent.getAgentId().equals(agentId)) {
+                return agent;
+            }
+        }
+        return null;
+    }
+
+    public Collection<BackendInformation> getBackends(String agentId) {
+        return backends.get(agentId);
+    }
+
+    public void refresh() {
+        agents.clear();
+        agents.addAll(agentInfoDao.getAllAgentInformation());
+        backends.clear();
+        for (AgentInformation agent : agents) {
+            String agentId = agent.getAgentId();
+            HostRef agentRef = new HostRef(agentId, agentId);
+            backends.put(agentId, backendInfoDao.getBackendInformation(agentRef));
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/AgentInformationDisplayView.java	Tue Sep 18 21:17:02 2012 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.ui;
+
+import java.util.Map;
+
+import com.redhat.thermostat.client.osgi.service.BasicView;
+import com.redhat.thermostat.common.ActionListener;
+
+public abstract class AgentInformationDisplayView extends BasicView {
+
+    enum ConfigurationAction {
+        SWITCH_AGENT,
+        SHOW_BACKEND_DESCRIPTION,
+        CLOSE,
+    }
+
+    public abstract void showDialog();
+
+    public abstract void hideDialog();
+
+    public abstract void addConfigurationListener(ActionListener<ConfigurationAction> listener);
+
+    public abstract void removeConfigurationListener(ActionListener<ConfigurationAction> listener);
+
+    public abstract void addAgent(String agentName);
+
+    public abstract String getSelectedAgent();
+
+    public abstract void clearAllAgents();
+
+    public abstract void setSelectedAgentName(String agentName);
+    public abstract void setSelectedAgentId(String agentId);
+    public abstract void setSelectedAgentCommandAddress(String address);
+    public abstract void setSelectedAgentStartTime(String startTime);
+    public abstract void setSelectedAgentStopTime(String stopTime);
+
+    public abstract void setSelectedAgentBackendStatus(Map<String, String> agentConfiguration);
+    public abstract void setSelectedAgentBackendDescription(String description);
+
+}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/ChartColors.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/ChartColors.java	Tue Sep 18 21:17:02 2012 +0200
@@ -38,15 +38,17 @@
 
 import java.awt.Color;
 
+import com.redhat.thermostat.swing.Palette;
+
 public class ChartColors {
-    private static final Color[] SERIES_COLORS = {
-        new Color(192,80,77),
-        new Color(79,129,189),
-        new Color(155,187,89),
-        new Color(128,100,162),
-        new Color(75,172,198),
-        new Color(128,128,128),
-        new Color(247,150,70),
+    private static final Palette[] SERIES_COLORS = {
+        Palette.PALE_RED,
+        Palette.SKY_BLUE,
+        Palette.TUNDRA_GREEN,
+        Palette.POMP_AND_POWER_VIOLET,
+        Palette.DIRTY_CYAN,
+        Palette.EARL_GRAY,
+        Palette.GRANITA_ORANGE,
     };
 
     private ChartColors() {
@@ -54,6 +56,6 @@
     }
 
     public static Color getColor(int index) {
-        return SERIES_COLORS[index % SERIES_COLORS.length];
+        return SERIES_COLORS[index % SERIES_COLORS.length].getColor();
     }
 }
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/MainWindow.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/MainWindow.java	Tue Sep 18 21:17:02 2012 +0200
@@ -405,16 +405,6 @@
         JMenu editMenu = new JMenu(localize(LocaleResources.MENU_EDIT));
         mainMenuBar.add(editMenu);
 
-        JMenuItem configureAgentMenuItem = new JMenuItem(localize(LocaleResources.MENU_EDIT_CONFIGURE_AGENT));
-        configureAgentMenuItem.setName("showAgentConfig");
-        configureAgentMenuItem.addActionListener(new java.awt.event.ActionListener() {
-            @Override
-            public void actionPerformed(java.awt.event.ActionEvent e) {
-                fireViewAction(Action.SHOW_AGENT_CONFIG);
-            }
-        });
-        editMenu.add(configureAgentMenuItem);
-
         JMenuItem configureClientMenuItem = new JMenuItem(localize(LocaleResources.MENU_EDIT_CONFIGURE_CLIENT));
         configureClientMenuItem.setName("showClientConfig");
         configureClientMenuItem.addActionListener(new java.awt.event.ActionListener() {
@@ -435,8 +425,20 @@
                 fireViewAction(Action.SWITCH_HISTORY_MODE);
             }
         });
+        editMenu.add(historyModeMenuItem);
 
-        editMenu.add(historyModeMenuItem);
+        JMenu viewMenu = new JMenu(localize(LocaleResources.MENU_VIEW));
+        mainMenuBar.add(viewMenu);
+        JMenuItem configureAgentMenuItem = new JMenuItem(localize(LocaleResources.MENU_VIEW_AGENTS));
+        configureAgentMenuItem.setName("showAgentConfig");
+        configureAgentMenuItem.addActionListener(new java.awt.event.ActionListener() {
+            @Override
+            public void actionPerformed(java.awt.event.ActionEvent e) {
+                fireViewAction(Action.SHOW_AGENT_CONFIG);
+            }
+        });
+        viewMenu.add(configureAgentMenuItem);
+
         JMenu helpMenu = new JMenu(localize(LocaleResources.MENU_HELP));
         helpMenu.getPopupMenu().setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1));
         mainMenuBar.add(helpMenu);
--- a/client/core/src/main/resources/com/redhat/thermostat/client/locale/strings.properties	Tue Sep 18 21:13:17 2012 +0200
+++ b/client/core/src/main/resources/com/redhat/thermostat/client/locale/strings.properties	Tue Sep 18 21:17:02 2012 +0200
@@ -17,9 +17,10 @@
 MENU_FILE = File
 MENU_FILE_EXIT = Exit
 MENU_EDIT = Edit
-MENU_EDIT_CONFIGURE_AGENT = Configure Agent...
 MENU_EDIT_CONFIGURE_CLIENT = Client Preferences...
 MENU_EDIT_ENABLE_HISTORY_MODE = Enable History Mode
+MENU_VIEW = View
+MENU_VIEW_AGENTS = View All Agents...
 MENU_HELP = Help
 MENU_HELP_ABOUT = About
 
@@ -143,9 +144,21 @@
 VM_CLASSES_CHART_LOADED_CLASSES_LABEL = Number of loaded classes
 VM_INFO_TAB_CLASSES = Classes
 
-CONFIGURE_AGENT_WINDOW_TITLE = Configure Agent Backends
-CONFIGURE_AGENT_AGENTS_LIST = Agents
-CONFIGURE_ENABLE_BACKENDS = Enable/Disable Backends
+AGENT_INFO_WINDOW_TITLE = Known Agents
+AGENT_INFO_AGENTS_LIST = Agents
+AGENT_INFO_AGENT_SECTION_TITLE = Agent Information
+AGENT_INFO_AGENT_NAME_LABEL = Name
+AGENT_INFO_AGENT_ID_LABEL = Id
+AGENT_INFO_AGENT_COMMAND_ADDRESS_LABEL = Command Channel Address
+AGENT_INFO_AGENT_START_TIME_LABEL = Start Time
+AGENT_INFO_AGENT_STOP_TIME_LABEL = Stop Time
+AGENT_INFO_AGENT_RUNNING = Running
+AGENT_INFO_BACKENDS_SECTION_TITLE = Backends
+AGENT_INFO_BACKEND_NAME_COLUMN = Name
+AGENT_INFO_BACKEND_STATUS_COLUMN = Status
+AGENT_INFO_BACKEND_STATUS_ACTIVE = Active
+AGENT_INFO_BACKEND_STATUS_INACTIVE = Inactive
+AGENT_INFO_BACKEND_DESCRIPTION_LABEL = Description
 
 CLIENT_PREFS_WINDOW_TITLE = Preferences
 CLIENT_PREFS_CONNECTION = Connection info
--- a/client/core/src/test/java/com/redhat/thermostat/client/internal/SwingViewFactoryTest.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/client/core/src/test/java/com/redhat/thermostat/client/internal/SwingViewFactoryTest.java	Tue Sep 18 21:17:02 2012 +0200
@@ -45,7 +45,7 @@
 import org.junit.Test;
 
 import com.redhat.thermostat.client.internal.SwingViewFactory;
-import com.redhat.thermostat.client.ui.AgentConfigurationView;
+import com.redhat.thermostat.client.ui.AgentInformationDisplayView;
 import com.redhat.thermostat.client.ui.ClientConfigurationView;
 import com.redhat.thermostat.client.ui.HostCpuView;
 import com.redhat.thermostat.client.ui.HostMemoryView;
@@ -63,7 +63,7 @@
 
         List<Class<? extends View>> knownViewClasses = new ArrayList<>();
 
-        knownViewClasses.add(AgentConfigurationView.class);
+        knownViewClasses.add(AgentInformationDisplayView.class);
         knownViewClasses.add(ClientConfigurationView.class);
         knownViewClasses.add(HostCpuView.class);
         knownViewClasses.add(HostMemoryView.class);
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/AgentConfigurationControllerTest.java	Tue Sep 18 21:13:17 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,233 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.ui;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.InOrder;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import com.redhat.thermostat.client.ui.AgentConfigurationView.ConfigurationAction;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.common.TimerFactory;
-import com.redhat.thermostat.common.appctx.ApplicationContext;
-import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
-
-public class AgentConfigurationControllerTest {
-
-    @Before
-    public void setUp() {
-        ApplicationContextUtil.resetApplicationContext();
-
-        /*
-         * Set up a mock timer factory that always executes actions synchronously on start();
-         */
-        TimerFactory tf = mock(TimerFactory.class);
-        Timer timer = mock(Timer.class);
-        final Runnable[] runnable = new Runnable[1];
-        doAnswer(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                runnable[0] = (Runnable) invocation.getArguments()[0];
-                return null;
-            }
-
-        }).when(timer).setAction(any(Runnable.class));
-
-        doAnswer(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                runnable[0].run();
-                return null;
-            }
-
-        }).when(timer).start();
-        when(tf.createTimer()).thenReturn(timer);
-        ApplicationContext.getInstance().setTimerFactory(tf);
-
-    }
-
-    @After
-    public void tearDown() {
-        ApplicationContextUtil.resetApplicationContext();
-    }
-
-    @Test
-    public void testAddingEnabledBackends() {
-        AgentConfigurationView view = mock(AgentConfigurationView.class);
-        AgentConfigurationModel model = mock(AgentConfigurationModel.class);
-        when(model.getAgents()).thenReturn(Arrays.asList(new String[]{"agent1"}));
-        List<String> backends = Arrays.asList(new String[] {"backend1", "backend2"});
-        when(model.getBackends(any(String.class))).thenReturn(backends);
-        when(model.getAgentBackendEnabled(any(String.class), any(String.class))).thenReturn(true);
-
-        Map<String,Boolean> expected = new HashMap<>();
-        expected.put("backend1", true);
-        expected.put("backend2", true);
-
-        AgentConfigurationController controller = new AgentConfigurationController(model, view);
-        controller.showView();
-        controller.hideView();
-
-        verify(view).addAgent("agent1");
-        verify(view).setBackendStatus(eq(expected));
-        verify(view).showDialog();
-        verify(view).hideDialog();
-    }
-
-    @Test
-    public void testAddingDisabledBackends() {
-        AgentConfigurationView view = mock(AgentConfigurationView.class);
-        AgentConfigurationModel model = mock(AgentConfigurationModel.class);
-        when(model.getAgents()).thenReturn(Arrays.asList(new String[]{"agent1"}));
-        List<String> backends = Arrays.asList(new String[] {"backend1",});
-        when(model.getBackends(any(String.class))).thenReturn(backends);
-        when(model.getAgentBackendEnabled(any(String.class), any(String.class))).thenReturn(false);
-
-        Map<String,Boolean> expected = new HashMap<>();
-        expected.put("backend1", false);
-
-        AgentConfigurationController controller = new AgentConfigurationController(model, view);
-        controller.showView();
-        controller.hideView();
-
-        verify(view).addAgent("agent1");
-        verify(view).setBackendStatus(eq(expected));
-        verify(view).showDialog();
-        verify(view).hideDialog();
-    }
-
-    /**
-     * Verify that the accepting the changes signals the controller
-     */
-    @SuppressWarnings("unchecked") // All this ActionListener fluff
-    @Test
-    public void testViewEditedBackends() {
-        final ActionListener<ConfigurationAction>[] listeners = (ActionListener<ConfigurationAction>[]) new ActionListener<?>[1];
-        AgentConfigurationView view = mock(AgentConfigurationView.class);
-        doAnswer(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                listeners[0] = (ActionListener<ConfigurationAction>) invocation.getArguments()[0];
-                return null;
-            }
-        }).when(view).addActionListener(any(ActionListener.class));
-
-
-        AgentConfigurationModel model = mock(AgentConfigurationModel.class);
-        when(model.getAgents()).thenReturn(Arrays.asList(new String[]{"agent1"}));
-        List<String> backends = Arrays.asList(new String[] {"backend1"});
-        when(model.getBackends(any(String.class))).thenReturn(backends);
-        when(model.getAgentBackendEnabled(any(String.class), any(String.class))).thenReturn(true);
-
-        Map<String,Boolean> expected = new HashMap<>();
-        expected.put("backend1", true);
-
-        AgentConfigurationController controller = new AgentConfigurationController(model, view);
-        controller.showView();
-
-        listeners[0].actionPerformed(new ActionEvent<ConfigurationAction>(view, ConfigurationAction.CLOSE_ACCEPT));
-
-        controller.hideView();
-
-        InOrder inOrder = inOrder(view);
-
-        inOrder.verify(view).addAgent("agent1");
-        inOrder.verify(view).setBackendStatus(eq(expected));
-        inOrder.verify(view).getBackendStatus();
-
-        verify(model).saveConfiguration();
-    }
-
-    /**
-     * Verify that controller handles cancel properly
-     */
-    @SuppressWarnings("unchecked") // All this ActionListener fluff.
-    @Test
-    public void testViewCancelEditingBackends() {
-        final ActionListener<ConfigurationAction>[] listeners = (ActionListener<ConfigurationAction>[]) new ActionListener<?>[1];
-        AgentConfigurationView view = mock(AgentConfigurationView.class);
-        doAnswer(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                listeners[0] = (ActionListener<ConfigurationAction>) invocation.getArguments()[0];
-                return null;
-            }
-        }).when(view).addActionListener(any(ActionListener.class));
-
-
-        AgentConfigurationModel model = mock(AgentConfigurationModel.class);
-        when(model.getAgents()).thenReturn(Arrays.asList(new String[]{"agent1"}));
-        List<String> backends = Arrays.asList(new String[] {"backend1"});
-        when(model.getBackends(any(String.class))).thenReturn(backends);
-        when(model.getAgentBackendEnabled(any(String.class), any(String.class))).thenReturn(true);
-
-        Map<String,Boolean> expectedConfig = new HashMap<>();
-        expectedConfig.put("backend1", true);
-
-        AgentConfigurationController controller = new AgentConfigurationController(model, view);
-        controller.showView();
-
-        listeners[0].actionPerformed(new ActionEvent<ConfigurationAction>(view, ConfigurationAction.CLOSE_CANCEL));
-
-        controller.hideView();
-
-        verify(view).addAgent("agent1");
-        verify(view).setBackendStatus(eq(expectedConfig));
-        verify(view, never()).getBackendStatus();
-
-        verify(model, never()).saveConfiguration();
-    }
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/AgentConfigurationFrameTest.java	Tue Sep 18 21:13:17 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.ui;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
-
-import org.fest.swing.edt.GuiActionRunner;
-import org.fest.swing.edt.GuiQuery;
-import org.fest.swing.edt.GuiTask;
-import org.fest.swing.fixture.FrameFixture;
-import org.fest.swing.fixture.JListFixture;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-
-@RunWith(CacioFESTRunner.class)
-public class AgentConfigurationFrameTest {
-
-    private AgentConfigurationFrame agentConfigFrame;
-    private FrameFixture fixture;
-    private ActionListener<AgentConfigurationView.ConfigurationAction> l;
-
-    @Before
-    public void setUp() {
-        agentConfigFrame = GuiActionRunner.execute(new GuiQuery<AgentConfigurationFrame>() {
-
-            @Override
-            protected AgentConfigurationFrame executeInEDT() throws Throwable {
-                 return new AgentConfigurationFrame();
-            }
-        });
-
-        @SuppressWarnings("unchecked")
-        ActionListener<AgentConfigurationView.ConfigurationAction> listener = mock(ActionListener.class);
-        l = listener;
-        agentConfigFrame.addActionListener(l);
-
-        fixture = new FrameFixture(agentConfigFrame);
-    }
-
-    @After
-    public void tearDown() {
-        GuiActionRunner.execute(new GuiTask() {
-            @Override
-            protected void executeInEDT() throws Throwable {
-                agentConfigFrame.hideDialog();
-            }
-        });
-
-        fixture.requireNotVisible();
-        agentConfigFrame.removeActionListener(l);
-
-        fixture.cleanUp();
-        fixture = null;
-    }
-
-    @Test
-    public void testAddingAgentWorks() {
-        fixture.show();
-        JListFixture list = fixture.list("agentList");
-        assertArrayEquals(new String[0], list.contents());
-
-        agentConfigFrame.addAgent("test-agent");
-
-        assertArrayEquals(new String[] {"test-agent"}, list.contents());
-    }
-
-    @Test
-    public void testSelectingAgentWorks() {
-        fixture.show();
-        agentConfigFrame.addAgent("testAgent");
-        JListFixture list = fixture.list("agentList");
-
-        list.selectItem("testAgent");
-
-        verify(l).actionPerformed(eq(new ActionEvent<>(agentConfigFrame, AgentConfigurationView.ConfigurationAction.SWITCH_AGENT)));
-    }
-
-    @Test
-    public void testRemovingAllAgentsWorks() {
-        fixture.show();
-        agentConfigFrame.addAgent("test-agent");
-        JListFixture list = fixture.list("agentList");
-
-        agentConfigFrame.clearAllAgents();
-
-        assertArrayEquals(new String[0], list.contents());
-    }
-
-    @Test
-    public void testWindowClose() {
-        fixture.show();
-
-        fixture.close();
-
-        verify(l).actionPerformed(eq(new ActionEvent<>(agentConfigFrame, AgentConfigurationView.ConfigurationAction.CLOSE_CANCEL)));
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/AgentInformationDisplayControllerTest.java	Tue Sep 18 21:17:02 2012 +0200
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.ui;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.client.ui.AgentInformationDisplayView.ConfigurationAction;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.model.AgentInformation;
+import com.redhat.thermostat.common.model.BackendInformation;
+
+public class AgentInformationDisplayControllerTest {
+
+    private AgentInformation agentInfo1;
+    private BackendInformation backendInfo1;
+
+    @Before
+    public void setUp() {
+        setUpAgentAndBackendInformation();
+    }
+
+    private void setUpAgentAndBackendInformation() {
+        agentInfo1 = new AgentInformation();
+        agentInfo1.setAgentId("agent-1");
+
+        backendInfo1 = new BackendInformation();
+        backendInfo1.setName("backend-1");
+        backendInfo1.setDescription("backend-description1");
+    }
+
+    @Test
+    public void testShowView() {
+        AgentInformationDisplayView view = mock(AgentInformationDisplayView.class);
+        AgentInformationDisplayModel model = mock(AgentInformationDisplayModel.class);
+
+        when(model.getAgents()).thenReturn(Arrays.asList(agentInfo1));
+        when(model.getAgentInfo(agentInfo1.getAgentId())).thenReturn(agentInfo1);
+
+        AgentInformationDisplayController controller = new AgentInformationDisplayController(model, view);
+        controller.showView();
+
+        verify(view).showDialog();
+    }
+
+    @Test
+    public void testHideView() {
+        AgentInformationDisplayView view = mock(AgentInformationDisplayView.class);
+        AgentInformationDisplayModel model = mock(AgentInformationDisplayModel.class);
+
+        AgentInformationDisplayController controller = new AgentInformationDisplayController(model, view);
+        controller.hideView();
+
+        verify(view).hideDialog();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testHidViewWhenViewFiresClose() {
+        AgentInformationDisplayView view = mock(AgentInformationDisplayView.class);
+        AgentInformationDisplayModel model = mock(AgentInformationDisplayModel.class);
+
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<ActionListener> captor = ArgumentCaptor.forClass(ActionListener.class);
+
+        @SuppressWarnings("unused")
+        AgentInformationDisplayController controller = new AgentInformationDisplayController(model, view);
+
+        verify(view).addConfigurationListener(captor.capture());
+        ActionListener<ConfigurationAction> listener = captor.getValue();
+        listener.actionPerformed(new ActionEvent<ConfigurationAction>(view, ConfigurationAction.CLOSE));
+
+        verify(view).hideDialog();
+    }
+
+    @Test
+    public void testAddAgentAndBackendsOnInit() {
+        AgentInformationDisplayView view = mock(AgentInformationDisplayView.class);
+        AgentInformationDisplayModel model = mock(AgentInformationDisplayModel.class);
+
+        when(model.getAgents()).thenReturn(Arrays.asList(agentInfo1));
+        when(model.getAgentInfo(agentInfo1.getAgentId())).thenReturn(agentInfo1);
+        when(model.getBackends(agentInfo1.getAgentId())).thenReturn(Arrays.asList(backendInfo1));
+
+        Map<String, String> expected = new HashMap<>();
+        expected.put(backendInfo1.getName(), backendInfo1.isActive() ? "Active" : "Inactive");
+
+        AgentInformationDisplayController controller = new AgentInformationDisplayController(model, view);
+        controller.showView();
+
+        verify(view).addAgent(agentInfo1.getAgentId());
+
+        verify(view).setSelectedAgentName(agentInfo1.getAgentId());
+        verify(view).setSelectedAgentId(agentInfo1.getAgentId());
+        verify(view).setSelectedAgentCommandAddress(agentInfo1.getConfigListenAddress());
+        verify(view).setSelectedAgentStartTime(isA(String.class));
+        verify(view).setSelectedAgentStopTime(isA(String.class));
+
+        verify(view).setSelectedAgentBackendStatus(eq(expected));
+        verify(view).showDialog();
+    }
+
+    @Test
+    public void testUpdateAgentInformationOnAgentSelection() {
+        AgentInformationDisplayView view = mock(AgentInformationDisplayView.class);
+        AgentInformationDisplayModel model = mock(AgentInformationDisplayModel.class);
+
+        when(model.getAgents()).thenReturn(Arrays.asList(agentInfo1));
+        when(model.getAgentInfo(agentInfo1.getAgentId())).thenReturn(agentInfo1);
+        when(model.getBackends(agentInfo1.getAgentId())).thenReturn(Arrays.asList(backendInfo1));
+
+        when(view.getSelectedAgent()).thenReturn(agentInfo1.getAgentId());
+
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<ActionListener> captor = ArgumentCaptor.forClass(ActionListener.class);
+
+        @SuppressWarnings("unused")
+        AgentInformationDisplayController controller = new AgentInformationDisplayController(model, view);
+
+        verify(view).addConfigurationListener(captor.capture());
+        ActionListener<ConfigurationAction> listener = captor.getValue();
+        listener.actionPerformed(new ActionEvent<ConfigurationAction>(view, ConfigurationAction.SWITCH_AGENT));
+
+        verify(view, never()).addAgent(agentInfo1.getAgentId());
+
+        verify(view).setSelectedAgentName(agentInfo1.getAgentId());
+        verify(view).setSelectedAgentId(agentInfo1.getAgentId());
+        verify(view).setSelectedAgentCommandAddress(agentInfo1.getConfigListenAddress());
+        verify(view).setSelectedAgentStartTime(isA(String.class));
+        verify(view).setSelectedAgentStopTime(isA(String.class));
+
+        Map<String, String> expected = new HashMap<>();
+        expected.put(backendInfo1.getName(), backendInfo1.isActive() ? "Active" : "Inactive");
+
+        verify(view).setSelectedAgentBackendStatus(eq(expected));
+    }
+
+    @Test
+    public void testUpdateDescriptionOnRequest() {
+        AgentInformationDisplayModel model = mock(AgentInformationDisplayModel.class);
+        AgentInformationDisplayView view = mock(AgentInformationDisplayView.class);
+
+        when(model.getAgents()).thenReturn(Arrays.asList(agentInfo1));
+        when(model.getAgentInfo(agentInfo1.getAgentId())).thenReturn(agentInfo1);
+        when(model.getBackends(agentInfo1.getAgentId())).thenReturn(Arrays.asList(backendInfo1));
+
+        when(view.getSelectedAgent()).thenReturn(agentInfo1.getAgentId());
+
+        Map<String, String> expected = new HashMap<>();
+        expected.put(backendInfo1.getName(), backendInfo1.isActive() ? "Active" : "Inactive");
+
+        ArgumentCaptor<ActionListener> listenerCaptor = ArgumentCaptor.forClass(ActionListener.class);
+        AgentInformationDisplayController controller = new AgentInformationDisplayController(model, view);
+
+        verify(view).addConfigurationListener(listenerCaptor.capture());
+
+        ActionEvent<ConfigurationAction> showBackendDescription = new ActionEvent<>(view, ConfigurationAction.SHOW_BACKEND_DESCRIPTION);
+        showBackendDescription.setPayload(backendInfo1.getName());
+
+        listenerCaptor.getValue().actionPerformed(showBackendDescription);
+
+        verify(view).setSelectedAgentBackendDescription(backendInfo1.getDescription());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/AgentInformationDisplayFrameTest.java	Tue Sep 18 21:17:02 2012 +0200
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.ui;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
+
+import org.fest.swing.annotation.GUITest;
+import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
+import org.fest.swing.edt.GuiActionRunner;
+import org.fest.swing.edt.GuiQuery;
+import org.fest.swing.edt.GuiTask;
+import org.fest.swing.fixture.FrameFixture;
+import org.fest.swing.fixture.JListFixture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import com.redhat.thermostat.client.ui.AgentInformationDisplayView.ConfigurationAction;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+
+@RunWith(CacioFESTRunner.class)
+public class AgentInformationDisplayFrameTest {
+
+    private AgentInformationDisplayFrame agentConfigFrame;
+    private FrameFixture fixture;
+    private ActionListener<AgentInformationDisplayView.ConfigurationAction> l;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+
+    @Before
+    public void setUp() {
+        agentConfigFrame = GuiActionRunner.execute(new GuiQuery<AgentInformationDisplayFrame>() {
+
+            @Override
+            protected AgentInformationDisplayFrame executeInEDT() throws Throwable {
+                return new AgentInformationDisplayFrame();
+            }
+        });
+
+        @SuppressWarnings("unchecked")
+        ActionListener<AgentInformationDisplayView.ConfigurationAction> listener = mock(ActionListener.class);
+        l = listener;
+        agentConfigFrame.addConfigurationListener(l);
+
+        fixture = new FrameFixture(agentConfigFrame.getFrame());
+    }
+
+    @After
+    public void tearDown() {
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                agentConfigFrame.hideDialog();
+            }
+        });
+
+        fixture.requireNotVisible();
+        agentConfigFrame.removeConfigurationListener(l);
+
+        fixture.cleanUp();
+        fixture = null;
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testWindowClose() {
+        fixture.show();
+
+        fixture.close();
+
+        verify(l).actionPerformed(eq(new ActionEvent<>(agentConfigFrame, AgentInformationDisplayView.ConfigurationAction.CLOSE)));
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testClickOnCloseButton() {
+        fixture.show();
+
+        fixture.button("close").click();
+
+        fixture.robot.waitForIdle();
+
+        verify(l).actionPerformed(eq(new ActionEvent<>(agentConfigFrame, AgentInformationDisplayView.ConfigurationAction.CLOSE)));
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testAddingAgentWorks() {
+        fixture.show();
+        JListFixture list = fixture.list("agentList");
+        assertArrayEquals(new String[0], list.contents());
+
+        agentConfigFrame.addAgent("test-agent");
+
+        assertArrayEquals(new String[] { "test-agent" }, list.contents());
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testSelectingAgentWorks() {
+        fixture.show();
+        agentConfigFrame.addAgent("testAgent");
+        JListFixture list = fixture.list("agentList");
+
+        list.selectItem("testAgent");
+
+        verify(l, atLeast(1)).actionPerformed(eq(new ActionEvent<>(agentConfigFrame, AgentInformationDisplayView.ConfigurationAction.SWITCH_AGENT)));
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testFirstAddedAgentIsAutomaticallySelected() {
+        fixture.show();
+        agentConfigFrame.addAgent("testAgent");
+
+        fixture.robot.waitForIdle();
+
+        verify(l).actionPerformed(eq(new ActionEvent<>(agentConfigFrame, AgentInformationDisplayView.ConfigurationAction.SWITCH_AGENT)));
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testRemovingAllAgentsWorks() {
+        fixture.show();
+        agentConfigFrame.addAgent("test-agent");
+        JListFixture list = fixture.list("agentList");
+
+        agentConfigFrame.clearAllAgents();
+
+        assertArrayEquals(new String[0], list.contents());
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testUpdatingAgentInformationWorks() {
+
+        final String AGENT_NAME = "the-agent-name";
+        final String AGENT_ID = "the-agent-id";
+        final String COMMAND_ADDRESS = "agent-command-channel-address";
+        final String START_TIME = "some-start-time";
+        final String STOP_TIME = "a-certain-stop-time";
+
+        agentConfigFrame.setSelectedAgentName(AGENT_NAME);
+        agentConfigFrame.setSelectedAgentId(AGENT_ID);
+        agentConfigFrame.setSelectedAgentCommandAddress(COMMAND_ADDRESS);
+        agentConfigFrame.setSelectedAgentStartTime(START_TIME);
+        agentConfigFrame.setSelectedAgentStopTime(STOP_TIME);
+
+        fixture.show();
+
+        assertEquals(AGENT_NAME, fixture.textBox("agentName").text());
+        assertEquals(AGENT_ID, fixture.textBox("agentId").text());
+        assertEquals(COMMAND_ADDRESS, fixture.textBox("commandAddress").text());
+        assertEquals(START_TIME, fixture.textBox("startTime").text());
+        assertEquals(STOP_TIME, fixture.textBox("stopTime").text());
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testBackendDescriptionIsQueriedAndDisplayed() {
+        final String BACKEND_NAME = "foo";
+        final String BACKEND_STATUS = "bar";
+        final String BACKEND_DESCRIPTION = "baz";
+
+        Map<String, String> statusMap = new HashMap<>();
+        statusMap.put(BACKEND_NAME, BACKEND_STATUS);
+
+        fixture.show();
+
+        agentConfigFrame.setSelectedAgentBackendStatus(statusMap);
+
+        assertEquals(1, fixture.table("backends").rowCount());
+
+        String[] rowContents = fixture.table("backends").contents()[0];
+        assertArrayEquals(new String[] { BACKEND_NAME, BACKEND_STATUS }, rowContents);
+
+        fixture.table("backends").selectRows(0);
+
+        verify(l).actionPerformed(new ActionEvent<ConfigurationAction>(agentConfigFrame, ConfigurationAction.SHOW_BACKEND_DESCRIPTION));
+
+        agentConfigFrame.setSelectedAgentBackendDescription(BACKEND_DESCRIPTION);
+
+        assertEquals(BACKEND_DESCRIPTION, fixture.textBox("backendDescription").text());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/AgentInformationDisplayModelTest.java	Tue Sep 18 21:17:02 2012 +0200
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.ui;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
+import com.redhat.thermostat.common.dao.BackendInfoDAO;
+import com.redhat.thermostat.common.dao.DAOFactory;
+import com.redhat.thermostat.common.model.AgentInformation;
+
+public class AgentInformationDisplayModelTest {
+
+    private AgentInformation agentInfo1 = new AgentInformation();
+    private AgentInformation agentInfo2 = new AgentInformation();
+
+    private DAOFactory daoFactory = mock(DAOFactory.class);
+    private AgentInfoDAO agentInfoDao = mock(AgentInfoDAO.class);
+    private BackendInfoDAO backendInfoDao = mock(BackendInfoDAO.class);
+
+    @Before
+    public void setUp() {
+        ApplicationContextUtil.resetApplicationContext();
+
+        when(daoFactory.getAgentInfoDAO()).thenReturn(agentInfoDao);
+        when(daoFactory.getBackendInfoDAO()).thenReturn(backendInfoDao);
+
+        agentInfo1.setAgentId("agent1-id");
+        agentInfo1.setStartTime(0);
+        agentInfo1.setStopTime(1);
+        agentInfo1.setConfigListenAddress("config-address:port");
+        agentInfo1.setAlive(false);
+
+        agentInfo2.setAgentId("agent2-id");
+
+        when(agentInfoDao.getAllAgentInformation()).thenReturn(Arrays.asList(agentInfo1));
+
+        ApplicationContext.getInstance().setDAOFactory(daoFactory);
+    }
+
+    @After
+    public void tearDown() {
+        ApplicationContextUtil.resetApplicationContext();
+    }
+
+    @Test
+    public void testModelInitializesItself() {
+        AgentInformationDisplayModel model = new AgentInformationDisplayModel();
+
+        AgentInformation agentInfoFromModel = model.getAgentInfo(agentInfo1.getAgentId());
+
+        assertEquals(agentInfo1, agentInfoFromModel);
+    }
+
+    @Test
+    public void testGetUnknownAgentInformation() {
+        AgentInformationDisplayModel model = new AgentInformationDisplayModel();
+
+        AgentInformation agentInfoFromModel = model.getAgentInfo("some unknown agent id");
+
+        assertEquals(null, agentInfoFromModel);
+    }
+
+    @Test
+    public void testChangesOnlyVisibleAfterRefresh() {
+        AgentInformationDisplayModel model = new AgentInformationDisplayModel();
+        AgentInformation agentInfoFromModel;
+
+        agentInfoFromModel = model.getAgentInfo(agentInfo1.getAgentId());
+
+        assertEquals(agentInfo1, agentInfoFromModel);
+
+        when(agentInfoDao.getAllAgentInformation()).thenReturn(Arrays.asList(agentInfo2));
+
+        agentInfoFromModel = model.getAgentInfo(agentInfo1.getAgentId());
+
+        assertEquals(agentInfo1, agentInfoFromModel);
+
+        model.refresh();
+
+        agentInfoFromModel = model.getAgentInfo(agentInfo1.getAgentId());
+
+        assertEquals(null, agentInfoFromModel);
+
+    }
+}
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/chart/OverviewChart.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/chart/OverviewChart.java	Tue Sep 18 21:17:02 2012 +0200
@@ -57,9 +57,8 @@
 import org.jfree.data.time.TimeSeriesCollection;
 
 import com.redhat.thermostat.charts.BytesTickUnit;
-import com.redhat.thermostat.charts.Chart;
 
-public class OverviewChart extends Chart {
+public class OverviewChart {
         
     private static final ColorUIResource MAIN_BAR_BASE_COLOR = new ColorUIResource(0x4A90D9);
 
@@ -84,8 +83,7 @@
         used.setDescription(secondarySeries);
     }
     
-    @Override
-    protected JFreeChart createChart(int width, int height, Color bgColor) {
+    public JFreeChart createChart(int height, Color bgColor) {
 
         TimeSeriesCollection dataset = new TimeSeriesCollection();
         
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/HeapSwingView.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/HeapSwingView.java	Tue Sep 18 21:17:02 2012 +0200
@@ -122,7 +122,7 @@
             @Override
             public void run() {
 
-                ChartPanel charts = new ChartPanel(model);
+                ChartPanel charts = new ChartPanel(model.createChart(stats.getWidth(), stats.getBackground()));
                 stats.setChartPanel(charts);
                 
                 stats.setMax(capacity);
--- a/client/swing-components/src/main/java/com/redhat/thermostat/charts/Chart.java	Tue Sep 18 21:13:17 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- * Copyright 2012 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.charts;
-
-import java.awt.Color;
-import java.awt.Graphics2D;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-
-import org.jfree.chart.JFreeChart;
-
-public abstract class Chart {
-    
-    public BufferedImage getChart(int width, int height, Color bgColor) {
-        JFreeChart chart = createChart(width, height, bgColor);
-        
-        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-        chart.draw((Graphics2D) image.getGraphics(), new Rectangle2D.Double(0, 0, width, height), null);
-        
-        return image;
-    }
-    
-    protected abstract JFreeChart createChart(int width, int height, Color bgColor);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/ActionButton.java	Tue Sep 18 21:17:02 2012 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2012 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.swing;
+
+import javax.swing.AbstractButton;
+import javax.swing.Icon;
+import javax.swing.JButton;
+
+@SuppressWarnings("serial")
+public class ActionButton extends JButton implements ToolbarButton {
+
+    private AbstractButton realButton;
+    
+    public ActionButton(final Icon icon) {
+        super(icon);
+        
+        realButton = new JButton() {
+            @Override
+            public int getWidth() {
+                return icon.getIconWidth() + 5;
+            }
+            
+            @Override
+            public int getHeight() {
+                return icon.getIconHeight() + 4;
+            }
+        };
+        setUI(new ActionButtonUI(realButton));
+        
+        setSize(realButton.getWidth(), realButton.getHeight());
+        setContentAreaFilled(false);
+        
+        setPreferredSize(getSize());
+        setMinimumSize(getSize());
+        setMaximumSize(getSize());
+        
+        realButton.setModel(getModel());
+
+        setBorderPainted(false);
+    }
+    
+    @Override
+    public AbstractButton getToolbarButton() {
+        return this;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/ActionButtonUI.java	Tue Sep 18 21:17:02 2012 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2012 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.swing;
+
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ConvolveOp;
+import java.awt.image.Kernel;
+
+import javax.swing.AbstractButton;
+import javax.swing.ButtonModel;
+import javax.swing.Icon;
+import javax.swing.JComponent;
+import javax.swing.border.Border;
+import javax.swing.plaf.metal.MetalButtonUI;
+
+class ActionButtonUI extends MetalButtonUI {
+
+    private BufferedImage sourceIcon;
+    private BufferedImage rollOverIcon;
+    private AbstractButton realButton;
+    
+    ActionButtonUI(AbstractButton button) {
+        this.realButton = button;
+    }
+    
+    private BufferedImage getBrighterImage(BufferedImage source) {
+        float[] kernel = new float[] { 0, 0, 0, 0, 1.2f, 0, 0, 0, 0 };
+
+        BufferedImageOp brighterOp = new ConvolveOp(new Kernel(3, 3, kernel),
+                ConvolveOp.EDGE_NO_OP, null);
+        return brighterOp.filter(source, new BufferedImage(source.getWidth(),
+                source.getHeight(), source.getType()));
+    }
+
+    @Override
+    public void paint(Graphics g, JComponent c) {
+
+        AbstractButton button = (AbstractButton) c;
+        ButtonModel model = button.getModel();
+        if (model.isPressed() || model.isArmed() || model.isSelected()) {
+            realButton.paint(g);
+        } else if (model.isRollover()) {
+            Border border = realButton.getBorder();
+            border.paintBorder(realButton, g, 0, 0, realButton.getWidth(),
+                    realButton.getHeight());
+        }
+        // paint the icon, always to the center
+        Icon icon = button.getIcon();
+        int w = icon.getIconWidth();
+        int h = icon.getIconHeight();
+
+        if (sourceIcon == null) {
+            sourceIcon = new BufferedImage(w + 1, h + 1,
+                    BufferedImage.TYPE_INT_ARGB);
+            Graphics imageGraphics = sourceIcon.getGraphics();
+            icon.paintIcon(null, imageGraphics, 0, 0);
+        }
+
+        if (rollOverIcon == null) {
+            rollOverIcon = getBrighterImage(sourceIcon);
+        }
+
+        int x = realButton.getWidth() / 2 - w / 2;
+        int y = realButton.getHeight() / 2 - h / 2;
+
+        if (model.isRollover()) {
+            g.drawImage(rollOverIcon, x, y, null);
+        } else {
+            g.drawImage(sourceIcon, x, y, null);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/ActionToggleButton.java	Tue Sep 18 21:17:02 2012 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2012 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.swing;
+
+import javax.swing.AbstractButton;
+import javax.swing.Icon;
+import javax.swing.JToggleButton;
+
+@SuppressWarnings("serial")
+public class ActionToggleButton extends JToggleButton implements ToolbarButton {
+    private AbstractButton realButton;
+    
+    public ActionToggleButton(final Icon icon) {
+        super(icon);
+        
+        realButton = new JToggleButton() {
+            @Override
+            public int getWidth() {
+                return icon.getIconWidth() + 4;
+            }
+            
+            @Override
+            public int getHeight() {
+                return icon.getIconHeight() + 4;
+            }
+        };
+        setUI(new ActionButtonUI(realButton));
+        
+        setSize(realButton.getWidth(), realButton.getHeight());
+        setContentAreaFilled(false);
+        
+        setPreferredSize(getSize());
+        setMinimumSize(getSize());
+        setMaximumSize(getSize());
+        
+        realButton.setModel(getModel());
+
+        setBorderPainted(false);
+    }
+    
+    @Override
+    public AbstractButton getToolbarButton() {
+        return this;
+    }    
+}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/ChartPanel.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/ChartPanel.java	Tue Sep 18 21:17:02 2012 +0200
@@ -41,20 +41,31 @@
 
 import javax.swing.JPanel;
 
-import com.redhat.thermostat.charts.Chart;
+import org.jfree.chart.ChartRenderingInfo;
+import org.jfree.chart.JFreeChart;
 
 @SuppressWarnings("serial")
 public class ChartPanel extends JPanel {
 
-    private Chart chart;
+    private JFreeChart chart;
+    private ChartRenderingInfo info;
     
-    public ChartPanel(Chart chart) {
+    public ChartPanel(JFreeChart chart) {
         this.chart = chart;
     }
     
+    public ChartPanel(JFreeChart chart, ChartRenderingInfo info) {
+        this.chart = chart;
+        this.info = info;
+    }
+    
     @Override
     protected void paintComponent(Graphics g) {
-        BufferedImage image = chart.getChart(getWidth(), getHeight(), getBackground());
+        BufferedImage image = chart.createBufferedImage(getWidth(), getHeight(), info);
         g.drawImage(image, 0, 0, null);
     }
+    
+    public ChartRenderingInfo getChartRenderingInfo() {
+        return info;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/EmptyIcon.java	Tue Sep 18 21:17:02 2012 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012 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.swing;
+
+import java.awt.Component;
+import java.awt.Graphics;
+
+import javax.swing.ImageIcon;
+
+@SuppressWarnings("serial")
+public class EmptyIcon extends ImageIcon  {
+
+    private int width;
+    private int height;
+    
+    public EmptyIcon() {
+        this(16, 16);
+    }
+    
+    public EmptyIcon(int width, int height) {
+        this.width = width;
+        this.height = height;
+    }
+    
+    @Override
+    public int getIconHeight() {
+        return height;
+    }
+    
+    @Override
+    public int getIconWidth() {
+        return width;
+    }
+    
+    @Override
+    public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
+        // no-op
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/GradientPanel.java	Tue Sep 18 21:17:02 2012 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012 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.swing;
+
+import java.awt.Color;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+
+import javax.swing.JPanel;
+
+
+@SuppressWarnings("serial")
+public class GradientPanel extends JPanel {
+
+    private Color top;
+    private Color bottom;
+    
+    public GradientPanel(Color top, Color bottom) {
+        this.top = top;
+        this.bottom = bottom;
+    }
+    
+    @Override
+    protected void paintComponent(Graphics g) {
+        
+        Graphics2D graphics = GraphicsUtils.getInstance().createAAGraphics(g);
+        
+        Paint gradient = new GradientPaint(0, 0, top, 0, getHeight(), bottom);
+        graphics.setPaint(gradient);
+        graphics.fillRect(0, 0, getWidth(), getHeight());
+        graphics.dispose();
+    }
+}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/HeaderPanel.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/HeaderPanel.java	Tue Sep 18 21:17:02 2012 +0200
@@ -36,69 +36,62 @@
 
 package com.redhat.thermostat.swing;
 
+import java.awt.BorderLayout;
 import java.awt.Color;
-import java.awt.Font;
-import java.awt.GradientPaint;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Paint;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
 import java.lang.reflect.InvocationTargetException;
 
 import javax.swing.BoxLayout;
-import javax.swing.GroupLayout;
-import javax.swing.GroupLayout.Alignment;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
 import javax.swing.JComponent;
 import javax.swing.JFrame;
+import javax.swing.JLabel;
 import javax.swing.JPanel;
-import javax.swing.LayoutStyle.ComponentPlacement;
 import javax.swing.SwingUtilities;
 
 /**
  * A component that host a panel with a nicely rendered header.
  */
+@SuppressWarnings("serial")
 public class HeaderPanel extends JPanel {
-
-    private GraphicsUtils graphicsUtils;
     
     private String header;
-    private boolean open;
     
     private JPanel contentPanel;
-        
+    private JLabel headerLabel;
+    private JPanel headerPanel;
+    private JPanel controlPanel;
+    
     public HeaderPanel() {
-        this(null);
+        this("");
     }
     
     public HeaderPanel(String header) {
-        this(header, 30);
-    }
-    
-    public HeaderPanel(String header, int headerHeight) {
         
         this.header = header;
-        graphicsUtils = GraphicsUtils.getInstance();
+        
+        setLayout(new BorderLayout(0, 0));
+
+        headerLabel = new ShadowLabel(header, new EmptyIcon(5, 5));
+        headerPanel = new GradientPanel(Color.WHITE, getBackground());
+        headerPanel.setPreferredSize(new Dimension(HeaderPanel.this.getWidth(), 40));
         
-        this.open = true;
+        headerPanel.setLayout(new BorderLayout(0, 0));
+        headerPanel.add(headerLabel, BorderLayout.WEST);
+        add(headerPanel, BorderLayout.NORTH);
         
-        JPanel headerPanel = new TopPanel();
+        controlPanel = new JPanel();
+        controlPanel.setOpaque(false);
+        controlPanel.setLayout(new FlowLayout(FlowLayout.RIGHT, 2, 10));
+        
+        headerPanel.add(controlPanel, BorderLayout.EAST);
         
         contentPanel = new JPanel();
         contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.X_AXIS));
         
-        GroupLayout groupLayout = new GroupLayout(this);
-        groupLayout.setHorizontalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addComponent(headerPanel, GroupLayout.DEFAULT_SIZE, 450, Short.MAX_VALUE)
-                .addComponent(contentPanel, GroupLayout.DEFAULT_SIZE, 450, Short.MAX_VALUE)
-        );
-        groupLayout.setVerticalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addComponent(headerPanel, GroupLayout.PREFERRED_SIZE, headerHeight, GroupLayout.PREFERRED_SIZE)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addComponent(contentPanel, GroupLayout.DEFAULT_SIZE, 260, Short.MAX_VALUE))
-        );
-        setLayout(groupLayout);
+        add(contentPanel, BorderLayout.CENTER);
     }
    
     public String getHeader() {
@@ -107,6 +100,7 @@
     
     public void setHeader(String header) {
         this.header = header;
+        headerLabel.setText(header);
     }
     
     public void setContent(JComponent content) {
@@ -115,27 +109,9 @@
         contentPanel.revalidate();
         repaint();
     }
-    
-    @SuppressWarnings({ "serial" })
-    private class TopPanel extends JPanel {
-        @Override
-        protected void paintComponent(Graphics g) {
-            
-            Graphics2D graphics = graphicsUtils.createAAGraphics(g);
-            
-            Paint gradient = new GradientPaint(0, 0, Color.WHITE, 0, getHeight(), getBackground());
-            graphics.setPaint(gradient);
-            graphics.fillRect(0, 0, getWidth(), getHeight());
-            
-            if (header != null) {
-                int currentHeight = getHeight();
-                
-                Font font = getFont();
-                int height = graphicsUtils.getFontMetrics(this, font).getAscent()/2 + currentHeight/2 - 1;
-                graphicsUtils.drawStringWithShadow(this, graphics, header, getForeground(), 6, height);
-            }
-            graphics.dispose();
-        }
+
+    public void addToolBarButton(ToolbarButton button) {
+        controlPanel.add(button.getToolbarButton());
     }
     
     public static void main(String[] args) throws InvocationTargetException, InterruptedException {
@@ -148,7 +124,7 @@
                
                HeaderPanel header = new HeaderPanel();
                header.setHeader("Test");
-               frame.add(header);
+               frame.getContentPane().add(header);
                frame.setSize(500, 500);
                frame.setVisible(true);
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/Palette.java	Tue Sep 18 21:17:02 2012 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012 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.swing;
+
+import java.awt.Color;
+
+public enum Palette {
+
+    RED(new Color(192, 0, 0)),
+    PALE_RED(new Color(192, 80, 77)),
+    
+    SKY_BLUE(new Color(79, 129, 189)),
+    AZUREUS(new Color(0, 176, 190)),
+    EGYPTIAN_BLUE(new Color(74, 144, 217)),
+    DIRTY_CYAN(new Color(75, 172, 198)),
+    PRUSSIAN_BLUE(new Color(0, 49, 83)),
+    
+    GREEN(new Color(146, 208, 80)),
+    TUNDRA_GREEN(new Color(155, 187, 89)),
+
+    POMP_AND_POWER_VIOLET(new Color(128, 100, 162)),
+    VIOLET(new Color(112, 48, 160)),
+
+    EARL_GRAY(new Color(128, 128, 128)),
+    LIGHT_GRAY(new Color(242, 242, 242)),
+    GRAY(new Color(216, 216, 216)),
+    DARK_GRAY(new Color(168, 172, 168)),
+
+    GRANITA_ORANGE(new Color(247,150,70)),
+    
+    BLACK(Color.BLACK),
+    WHITE(Color.WHITE),
+
+    /* END */ ;
+    
+    private Color color;
+    Palette(Color color) {
+        this.color = color;
+    }
+    
+    public Color getColor() {
+        return color;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/ShadowLabel.java	Tue Sep 18 21:17:02 2012 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2012 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.swing;
+
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+
+import javax.swing.Icon;
+import javax.swing.JLabel;
+import javax.swing.plaf.metal.MetalLabelUI;
+
+@SuppressWarnings("serial")
+public class ShadowLabel extends JLabel {
+
+    public ShadowLabel(String text, Icon icon) {
+        super(text);
+        this.setIcon(icon);
+        setUI(new ShadowLabelUI());
+    }
+    
+    public ShadowLabel(String text) {
+        this(text, null);
+    }
+
+    private class ShadowLabelUI extends MetalLabelUI {
+        
+        @Override
+        protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, int textY) {
+            GraphicsUtils graphicsUtils = GraphicsUtils.getInstance();
+            Graphics2D graphics = graphicsUtils.createAAGraphics(g);
+            graphicsUtils.drawStringWithShadow(l, graphics, s, getForeground(), textX, textY);
+        }
+    }
+}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/ToggleButton.java	Tue Sep 18 21:13:17 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,176 +0,0 @@
-/*
- * Copyright 2012 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.swing;
-
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Container;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.RenderingHints;
-import java.beans.Transient;
-
-import javax.swing.ImageIcon;
-import javax.swing.JFrame;
-import javax.swing.JPanel;
-import javax.swing.JToggleButton;
-import javax.swing.SwingUtilities;
-import javax.swing.UIManager;
-
-/**
- * A simple On/Off switch.
- */
-@SuppressWarnings("serial")
-public class ToggleButton extends JToggleButton {
-    
-    private static final int WIDTH = 40;
-    private static final int HEIGHT = 24;
-    
-    private ImageIcon toggle;
-    private ImageIcon selectedToggle;
-    
-    public ToggleButton() {
-        
-        toggle = new ImageIcon(getClass().getResource("/icons/scale-slider-vert.png"));
-        selectedToggle = new ImageIcon(getClass().getResource("/icons/scale-slider-vert-backdrop.png"));
-        
-        setBorder(null);
-    }
-
-    @Override
-    protected void paintComponent(Graphics g) {
-        GraphicsUtils utils = GraphicsUtils.getInstance();
-        
-        Graphics2D graphics = utils.createAAGraphics(g);
-        graphics.clearRect(0, 0, getWidth(), getHeight());
-        
-        graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
-        
-        Color selectedcolor = null;
-        Color shadow = new Color(0xE0E0E0);
-        if (model.isSelected()) {
-            selectedcolor = new Color(0x4A90D9);
-        } else {
-            selectedcolor = new Color(0xaeaeae);
-        }
-        
-        Color bgColor = null;
-        Container parent = getParent();
-        if (parent != null) {
-            bgColor = parent.getBackground();
-        } else {
-            bgColor = getBackground();
-        }
-        
-        // external shape and main fill
-        utils.setGradientPaint(graphics, 0, 10, shadow, bgColor);
-        graphics.fill(utils.getRoundShape(getWidth(), getHeight()));
-        
-        utils.setGradientPaint(graphics, 0, getWidth() / 2, selectedcolor, bgColor);
-        graphics.draw(utils.getRoundShape(getWidth(), getHeight()));
-        
-        // slider
-        int x = (toggle.getIconWidth() / 2);
-        int y = (getHeight()/2);
-        int width = getWidth() - (toggle.getIconWidth()/2) - 2;
-        
-        graphics.setColor(selectedcolor);
-        graphics.setStroke(new BasicStroke(1.2f));
-        graphics.drawLine(x, y, width, y);
-        
-        graphics.setStroke(new BasicStroke());
-
-        // toggle
-        x = 2;
-        y = (getHeight()/2) - (toggle.getIconHeight()/2);
-        ImageIcon toggle = this.toggle;
-        if (model.isRollover()) {
-            toggle = this.selectedToggle;
-        }
-        
-        if (model.isSelected()) {
-            toggle = this.selectedToggle;
-            x = getWidth() - toggle.getIconWidth() - 3;
-        }
-        graphics.drawImage(toggle.getImage(), x, y, null);
-        
-        graphics.dispose();
-    }
-    
-    @Override
-    @Transient
-    public Dimension getMinimumSize() {
-        if (isMinimumSizeSet()) {
-            return super.getMinimumSize();
-        }
-        return new Dimension(WIDTH, HEIGHT);
-    }
-    
-    @Override
-    @Transient
-    public Dimension getPreferredSize() {
-        if (isPreferredSizeSet()) {
-            return super.getPreferredSize();
-        }
-        return new Dimension(WIDTH, HEIGHT);
-    }
-    
-    public static void main(String[] args) {
-        SwingUtilities.invokeLater(new Runnable() {
-            
-            @Override
-            public void run() {
-                JFrame frame = new JFrame();
-                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-                
-                HeaderPanel header = new HeaderPanel();
-                header.setHeader("Test");
-                
-                JPanel buttonPanel = new JPanel();
-                ToggleButton toggle = new ToggleButton();
-                
-                buttonPanel.add(toggle);
-                header.setContent(buttonPanel);
-                
-                frame.add(header);
-                frame.setSize(500, 500);
-                frame.setVisible(true);
-            }
-        });
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/ToolbarButton.java	Tue Sep 18 21:17:02 2012 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012 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.swing;
+
+import javax.swing.AbstractButton;
+
+public interface ToolbarButton {
+    AbstractButton getToolbarButton();
+}
--- a/dolphin/src/main/java/com/redhat/swing/laf/dolphin/button/DolphinButtonUI.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/dolphin/src/main/java/com/redhat/swing/laf/dolphin/button/DolphinButtonUI.java	Tue Sep 18 21:17:02 2012 +0200
@@ -90,13 +90,12 @@
         DolphinTheme theme = DolphinThemeUtils.getCurrentTheme();
         
         Graphics2D graphics = (Graphics2D) g.create();
-        
-        graphics.clearRect(0, 0, c.getWidth(), c.getHeight());
-        DolphinThemeUtils.setAntialiasing(graphics);
 
         AbstractButton button = (AbstractButton) c;
         ButtonModel model = button.getModel();
         
+        DolphinThemeUtils.setAntialiasing(graphics);
+
         Color topGradient = null;
         Color bottomGradient = null;
         if (!c.isEnabled()) {
@@ -111,17 +110,22 @@
                 bottomGradient = theme.getButtonGradientBottomColor();
             }
         }
+
+        if (button.isOpaque()) {
+            graphics.clearRect(0, 0, c.getWidth(), c.getHeight());
+        }
         
-        Paint paint = new GradientPaint(0, 0, topGradient, 0, c.getHeight(),
-                                        bottomGradient);
-        graphics.setPaint(paint);
+        if (button.isContentAreaFilled() && button.isOpaque()) {
+            Paint paint = new GradientPaint(0, 0, topGradient, 0, c.getHeight(),
+                    bottomGradient);
+            graphics.setPaint(paint);
+            Shape shape = DolphinThemeUtils.getRoundShape(c.getWidth(), c.getHeight());
+            graphics.fill(shape);
+        }
 
-        Shape shape = DolphinThemeUtils.getRoundShape(c.getWidth(), c.getHeight());
-        
-        graphics.fill(shape);
         graphics.dispose();
         
-        super.paint(g, c);        
+        super.paint(g, c);
     }
     
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/IconResources.java	Tue Sep 18 21:17:02 2012 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2012 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.thread.client.common;
+
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.client.ui.IconDescriptor;
+
+public class IconResources {
+
+    private static final Logger logger = Logger.getLogger(IconResources.class.getSimpleName());
+
+    private static IconDescriptor monitor;
+    private static IconDescriptor record;
+
+    public static IconDescriptor getMonitorIcon() {
+        if (monitor == null) {
+            monitor = loadIcon("com/redhat/thermostat/thread/client/common/monitor.png");
+        }
+        return monitor;
+    }
+    
+    public static IconDescriptor getRecordIcon() {
+        if (record == null) {
+            record = loadIcon("com/redhat/thermostat/thread/client/common/gtk-media-record.png");
+        }
+        return record;
+    }
+    
+    private static IconDescriptor loadIcon(String name) {
+        try {
+            return IconDescriptor.createFromClassloader(ClassLoader.getSystemClassLoader(), name);
+        } catch (IOException e) {
+            logger.log(Level.WARNING, "Can't load " + name, e);
+        }
+        return null;
+    }
+}
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadDetailsView.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadDetailsView.java	Tue Sep 18 21:17:02 2012 +0200
@@ -36,25 +36,13 @@
 
 package com.redhat.thermostat.thread.client.common;
 
-import java.io.IOException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
 import com.redhat.thermostat.client.osgi.service.BasicView;
 import com.redhat.thermostat.client.ui.IconDescriptor;
 
 public abstract class ThreadDetailsView extends BasicView {
-    
-    private static final Logger logger = Logger.getLogger(ThreadDetailsView.class.getSimpleName());
-    
+        
     public IconDescriptor getEmptyDetailsIcon() {
-        try {
-            return IconDescriptor.createFromClassloader(ClassLoader.getSystemClassLoader(),
-                                                        "com/redhat/thermostat/thread/client/common/monitor.png");
-        } catch (IOException e) {
-            logger.log(Level.WARNING, "Can't load emptyDetailsIcon", e);
-        }
-        return null;
+        return IconResources.getMonitorIcon();
     }
     
     public abstract void setDetails(ThreadTableBean thread);
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/chart/LivingDaemonThreadDifferenceChart.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/chart/LivingDaemonThreadDifferenceChart.java	Tue Sep 18 21:17:02 2012 +0200
@@ -47,7 +47,6 @@
 import org.jfree.chart.JFreeChart;
 import org.jfree.chart.axis.DateAxis;
 import org.jfree.chart.axis.NumberAxis;
-import org.jfree.chart.axis.TickUnits;
 import org.jfree.chart.axis.ValueAxis;
 import org.jfree.chart.plot.XYPlot;
 import org.jfree.chart.renderer.xy.XYDifferenceRenderer;
@@ -56,10 +55,7 @@
 import org.jfree.data.time.TimeSeries;
 import org.jfree.data.time.TimeSeriesCollection;
 
-import com.redhat.thermostat.charts.BytesTickUnit;
-import com.redhat.thermostat.charts.Chart;
-
-public class LivingDaemonThreadDifferenceChart extends Chart {
+public class LivingDaemonThreadDifferenceChart {
     
     private static final ColorUIResource MAIN_BAR_BASE_COLOR = new ColorUIResource(0x4A90D9);
 
@@ -85,8 +81,7 @@
         used.setDescription(secondarySeries);
     }
     
-    @Override
-    protected JFreeChart createChart(int width, int height, Color bgColor) {
+    public JFreeChart createChart(int height, Color bgColor) {
 
         TimeSeriesCollection dataset = new TimeSeriesCollection();
         
@@ -116,12 +111,13 @@
         plot.setDomainPannable(true);
         XYDifferenceRenderer r = new XYDifferenceRenderer(paint, paint2, false);
         r.setRoundXCoordinates(true);
+        
         plot.setDomainCrosshairLockedOnData(true);
         plot.setRangeCrosshairLockedOnData(true);
         plot.setDomainCrosshairVisible(true);
         plot.setRangeCrosshairVisible(true);
         plot.setRenderer(r);
-
+        
         ValueAxis domainAxis = new DateAxis(xAxis);
         domainAxis.setLowerMargin(0.0);
         domainAxis.setUpperMargin(0.0);
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/chart/ThreadDeatailsPieChart.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/chart/ThreadDeatailsPieChart.java	Tue Sep 18 21:17:02 2012 +0200
@@ -36,18 +36,15 @@
 
 package com.redhat.thermostat.thread.client.common.chart;
 
-import java.awt.Color;
-
 import org.jfree.chart.ChartFactory;
 import org.jfree.chart.JFreeChart;
 import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
 import org.jfree.chart.plot.PiePlot3D;
 import org.jfree.data.general.DefaultPieDataset;
 
-import com.redhat.thermostat.charts.Chart;
 import com.redhat.thermostat.thread.client.common.ThreadTableBean;
 
-public class ThreadDeatailsPieChart extends Chart {
+public class ThreadDeatailsPieChart {
     
     private ThreadTableBean thread;
     
@@ -55,8 +52,7 @@
         this.thread = thread;
     }
     
-    @Override
-    protected JFreeChart createChart(int width, int height, Color bgColor) {
+    public JFreeChart createChart() {
         
         DefaultPieDataset dataset = new DefaultPieDataset();
         
@@ -76,13 +72,11 @@
         chart.setAntiAlias(true);
         
         PiePlot3D plot = (PiePlot3D) chart.getPlot();
-        plot.setBackgroundPaint(bgColor);
         
         plot.setStartAngle(290);
         plot.setForegroundAlpha(0.5f);
 
         plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0} - {2}"));
-        plot.setBackgroundPaint(bgColor);
         
         plot.setInteriorGap(0.0);
         
Binary file thread/client-common/src/main/resources/com/redhat/thermostat/thread/client/common/gtk-media-record.png has changed
Binary file thread/client-common/src/main/resources/com/redhat/thermostat/thread/client/common/record.png has changed
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadDetailsView.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadDetailsView.java	Tue Sep 18 21:17:02 2012 +0200
@@ -82,7 +82,7 @@
         
         ThreadDetailsChart threadChart = new ThreadDetailsChart();
         
-        ChartPanel threadSummary = new ChartPanel(new ThreadDeatailsPieChart(thread));
+        ChartPanel threadSummary = new ChartPanel(new ThreadDeatailsPieChart(thread).createChart());
         threadChart.add(threadSummary);
         
         details.add(threadChart);
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadView.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadView.java	Tue Sep 18 21:17:02 2012 +0200
@@ -108,20 +108,19 @@
         });
         
         timelinePanel = new ThreadAliveDaemonTimelinePanel();
-
-        timelinePanel.setToggleText(t.localize(LocaleResources.START_RECORDING) + ":");
-        timelinePanel.getRecordButton().addItemListener(new ItemListener()
+        panel.getToggleButton().setToolTipText(t.localize(LocaleResources.START_RECORDING));
+        panel.getToggleButton().addItemListener(new ItemListener()
         {
             @Override
             public void itemStateChanged(ItemEvent e) {
-                                
-                ThreadAction action = null;
+                
+                ThreadAction action = null;                
                 if (e.getStateChange() == ItemEvent.SELECTED) {
                     action = ThreadAction.START_LIVE_RECORDING;
-                    timelinePanel.setToggleText(t.localize(LocaleResources.STOP_RECORDING) + ":");
+                    panel.getToggleButton().setToolTipText(t.localize(LocaleResources.STOP_RECORDING));
                 } else {
                     action = ThreadAction.STOP_LIVE_RECORDING;
-                    timelinePanel.setToggleText(t.localize(LocaleResources.START_RECORDING) + ":");
+                    panel.getToggleButton().setToolTipText(t.localize(LocaleResources.START_RECORDING));
                 }
                 
                 if (skipNotification) return;
@@ -173,7 +172,7 @@
             @Override
             public void run() {
                 if (!notify) skipNotification = true;
-                timelinePanel.getRecordButton().setSelected(recording);
+                panel.getToggleButton().setSelected(recording);
                 if (!notify) skipNotification = false;
             }
         });
@@ -207,7 +206,7 @@
                 JPanel pane = timelinePanel.getTimelinePanel();
                 pane.removeAll();
                 
-                ChartPanel charts = new ChartPanel(model);
+                ChartPanel charts = new ChartPanel(model.createChart(pane.getWidth(), pane.getBackground()));
                 pane.add(charts);
                 pane.revalidate();
                 pane.repaint();
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadAliveDaemonTimelinePanel.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadAliveDaemonTimelinePanel.java	Tue Sep 18 21:17:02 2012 +0200
@@ -46,7 +46,6 @@
 
 import com.redhat.thermostat.common.locale.Translate;
 import com.redhat.thermostat.thread.client.common.locale.LocaleResources;
-import com.redhat.thermostat.swing.ToggleButton;
 
 @SuppressWarnings("serial")
 class ThreadAliveDaemonTimelinePanel extends JPanel {
@@ -56,10 +55,6 @@
     private JLabel liveThreads;
     private JLabel daemonThreads;
     private JPanel timelinePanel;
-
-    private ToggleButton toggleButton;
-    
-    private JLabel lblNewLabel; 
     
     /**
      * Create the panel.
@@ -96,60 +91,29 @@
         
         daemonThreads = new JLabel("-");
         daemonThreads.setHorizontalAlignment(SwingConstants.RIGHT);
-        
-        JPanel panel = new JPanel();
         GroupLayout gl_runningPanel = new GroupLayout(runningPanel);
         gl_runningPanel.setHorizontalGroup(
             gl_runningPanel.createParallelGroup(Alignment.LEADING)
                 .addGroup(gl_runningPanel.createSequentialGroup()
-                    .addGroup(gl_runningPanel.createParallelGroup(Alignment.LEADING)
-                        .addComponent(daemonThreadsLabel)
-                        .addComponent(liveThreadsLabel))
-                    .addGap(24)
-                    .addGroup(gl_runningPanel.createParallelGroup(Alignment.LEADING, false)
-                        .addComponent(daemonThreads, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                        .addComponent(liveThreads, GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE))
+                    .addComponent(liveThreadsLabel)
+                    .addGap(18)
+                    .addComponent(liveThreads, GroupLayout.PREFERRED_SIZE, 85, GroupLayout.PREFERRED_SIZE)
+                    .addGap(18)
+                    .addComponent(daemonThreadsLabel)
                     .addPreferredGap(ComponentPlacement.RELATED)
-                    .addComponent(panel, GroupLayout.DEFAULT_SIZE, 331, Short.MAX_VALUE))
+                    .addComponent(daemonThreads, GroupLayout.PREFERRED_SIZE, 49, GroupLayout.PREFERRED_SIZE)
+                    .addContainerGap(54, Short.MAX_VALUE))
         );
         gl_runningPanel.setVerticalGroup(
             gl_runningPanel.createParallelGroup(Alignment.TRAILING)
-                .addGroup(gl_runningPanel.createSequentialGroup()
+                .addGroup(Alignment.LEADING, gl_runningPanel.createSequentialGroup()
                     .addGroup(gl_runningPanel.createParallelGroup(Alignment.BASELINE)
                         .addComponent(liveThreadsLabel)
-                        .addComponent(liveThreads))
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addGroup(gl_runningPanel.createParallelGroup(Alignment.BASELINE)
+                        .addComponent(liveThreads)
                         .addComponent(daemonThreads)
                         .addComponent(daemonThreadsLabel))
-                    .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
-                .addComponent(panel, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 48, Short.MAX_VALUE)
+                    .addContainerGap(26, Short.MAX_VALUE))
         );
-        
-        toggleButton = new ToggleButton();
-        toggleButton.setName("recordButton");
-        
-        lblNewLabel = new JLabel("New label");
-        lblNewLabel.setName("recordButtonText");
-        
-        GroupLayout gl_panel = new GroupLayout(panel);
-        gl_panel.setHorizontalGroup(
-            gl_panel.createParallelGroup(Alignment.TRAILING)
-                .addGroup(gl_panel.createSequentialGroup()
-                    .addContainerGap(209, Short.MAX_VALUE)
-                    .addComponent(lblNewLabel)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addComponent(toggleButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-        );
-        gl_panel.setVerticalGroup(
-            gl_panel.createParallelGroup(Alignment.LEADING)
-                .addGroup(gl_panel.createSequentialGroup()
-                    .addGroup(gl_panel.createParallelGroup(Alignment.TRAILING, false)
-                        .addComponent(lblNewLabel, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                        .addComponent(toggleButton, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
-                    .addContainerGap(24, Short.MAX_VALUE))
-        );
-        panel.setLayout(gl_panel);
         runningPanel.setLayout(gl_runningPanel);
         setLayout(groupLayout);
 
@@ -166,12 +130,4 @@
     public JPanel getTimelinePanel() {
         return timelinePanel;
     }
-    
-    public ToggleButton getRecordButton() {
-        return toggleButton;
-    }
-    
-    public void setToggleText(String text) {
-        lblNewLabel.setText(text);
-    }
 }
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadMainPanel.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadMainPanel.java	Tue Sep 18 21:17:02 2012 +0200
@@ -38,12 +38,15 @@
 
 import javax.swing.BoxLayout;
 import javax.swing.GroupLayout;
+import javax.swing.ImageIcon;
 import javax.swing.GroupLayout.Alignment;
 import javax.swing.JPanel;
 import javax.swing.JSplitPane;
 
 import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.swing.ActionToggleButton;
 import com.redhat.thermostat.swing.HeaderPanel;
+import com.redhat.thermostat.thread.client.common.IconResources;
 import com.redhat.thermostat.thread.client.common.locale.LocaleResources;
 
 @SuppressWarnings("serial")
@@ -52,6 +55,8 @@
     private static final Translate t = LocaleResources.createLocalizer();
     private JSplitPane splitPane;
     
+    private ActionToggleButton toggleButton;
+    
     public ThreadMainPanel() {
         setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
         
@@ -61,6 +66,10 @@
         JPanel content = new JPanel();
         headerPanel.setContent(content);
         
+        toggleButton = new ActionToggleButton(new ImageIcon(IconResources.getRecordIcon().getData().array()));
+        toggleButton.setName("recordButton");
+        headerPanel.addToolBarButton(toggleButton);
+        
         splitPane = new JSplitPane();
         splitPane.setName("threadMainPanelSplitPane");
         splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
@@ -90,4 +99,8 @@
     public JSplitPane getSplitPane() {
         return splitPane;
     }
+    
+    public ActionToggleButton getToggleButton() {
+        return toggleButton;
+    }
 }
--- a/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadViewTest.java	Tue Sep 18 21:13:17 2012 +0200
+++ b/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadViewTest.java	Tue Sep 18 21:17:02 2012 +0200
@@ -123,23 +123,22 @@
         frameFixture.show();
         
         JToggleButtonFixture togglefixture = frameFixture.toggleButton("recordButton");
-        JLabelFixture toggleTest = frameFixture.label("recordButtonText");
         
-        toggleTest.requireText(t.localize(LocaleResources.START_RECORDING) + ":");
+        togglefixture.requireToolTip(t.localize(LocaleResources.START_RECORDING));
         
         togglefixture.click();
 
-        toggleTest.requireText(t.localize(LocaleResources.STOP_RECORDING) + ":");
+        togglefixture.requireToolTip(t.localize(LocaleResources.STOP_RECORDING));
         
         // now try "programmatically"
         
         view.setRecording(true, true);
         
-        toggleTest.requireText(t.localize(LocaleResources.STOP_RECORDING) + ":");
+        togglefixture.requireToolTip(t.localize(LocaleResources.STOP_RECORDING));
     
         view.setRecording(false, false);
         
-        toggleTest.requireText(t.localize(LocaleResources.START_RECORDING) + ":");
+        togglefixture.requireToolTip(t.localize(LocaleResources.START_RECORDING));
     }
 
     @GUITest