changeset 585:23f5dedff60d

Merge
author Roman Kennke <rkennke@redhat.com>
date Tue, 04 Sep 2012 21:19:29 +0200
parents d480b69be1d7 (current diff) ed3f6e0a3867 (diff)
children 5786978e31e0
files
diffstat 10 files changed, 468 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/MainView.java	Tue Sep 04 20:58:27 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/internal/MainView.java	Tue Sep 04 21:19:29 2012 +0200
@@ -84,6 +84,8 @@
 
     void setSubView(BasicView view);
 
+    void setStatusBarPrimaryStatus(String primaryStatus);
+    
     /**
      * Adds a menu item to the window. Assumes the menu path is valid (has a
      * non-zero length) and doesn't collide with existing menus.
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/MainWindowControllerImpl.java	Tue Sep 04 20:58:27 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/internal/MainWindowControllerImpl.java	Tue Sep 04 21:19:29 2012 +0200
@@ -398,11 +398,14 @@
             HostRef hostRef = (HostRef) ref;
             HostInformationController hostController = facadeFactory.getHostController(hostRef);
             view.setSubView(hostController.getView());
+            view.setStatusBarPrimaryStatus("host: " + hostRef.getHostName() + ", id: " + hostRef.getAgentId());
         } else if (ref instanceof VmRef) {
             VmRef vmRef = (VmRef) ref;
             VmInformationController vmInformation =
                     vmInfoControllerProvider.getVmInfoController(vmRef);
             view.setSubView(vmInformation.getView());
+            view.setStatusBarPrimaryStatus("vm: " + vmRef.getName() + ", pid: " + vmRef.getStringID() +
+                                           ", host: " + vmRef.getAgent().getHostName());
         } else {
             throw new IllegalArgumentException("unknown type of ref");
         }
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/MainWindow.java	Tue Sep 04 20:58:27 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/MainWindow.java	Tue Sep 04 21:19:29 2012 +0200
@@ -110,6 +110,7 @@
 import com.redhat.thermostat.common.dao.VmRef;
 import com.redhat.thermostat.common.utils.StringUtils;
 import com.redhat.thermostat.swing.EdtHelper;
+import com.redhat.thermostat.swing.StatusBar;
 
 public class MainWindow extends JFrame implements MainView {
 
@@ -318,6 +319,7 @@
     private ActionNotifier<Action> actionNotifier = new ActionNotifier<>(this);
 
     private JPopupMenu vmContextMenu;
+    private StatusBar statusBar;
     
     private final DefaultMutableTreeNode publishedRoot =
             new DefaultMutableTreeNode(localize(LocaleResources.MAIN_WINDOW_TREE_ROOT_NAME));
@@ -368,6 +370,9 @@
         //agentVmTree.setLargeModel(true);
         agentVmTree.setRowHeight(25);
         
+        statusBar = new StatusBar();
+        getContentPane().add(statusBar, BorderLayout.SOUTH);
+        
         setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
         addWindowListener(shutdownAction);
 
@@ -466,7 +471,7 @@
         registerContextActionListener(agentVmTree);
         
         JScrollPane treeScrollPane = new JScrollPane(agentVmTree);
-
+        
         navigationPanel.add(treeScrollPane);
 
         JPanel detailsPanel = createDetailsPanel();
@@ -477,7 +482,7 @@
         splitPane.add(navigationPanel);
         splitPane.add(detailsPanel);
 
-        add(splitPane);
+        getContentPane().add(splitPane);
     }
 
     private void registerContextActionListener(JTree agentVmTree2) {
@@ -714,6 +719,16 @@
     }
 
     @Override
+    public void setStatusBarPrimaryStatus(final String primaryStatus) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                statusBar.setPrimaryStatus(primaryStatus);
+            }
+        });
+    }
+    
+    @Override
     public void setSubView(final BasicView view) {
         if (view instanceof SwingComponent) {
             final SwingComponent swingComp = (SwingComponent)view;
--- a/client/core/src/test/java/com/redhat/thermostat/client/internal/MainWindowControllerImplTest.java	Tue Sep 04 20:58:27 2012 +0200
+++ b/client/core/src/test/java/com/redhat/thermostat/client/internal/MainWindowControllerImplTest.java	Tue Sep 04 21:19:29 2012 +0200
@@ -398,6 +398,12 @@
     public void verifyOpenSameHostVMTab() {
 
         VmRef vmRef = mock(VmRef.class);
+        when(vmRef.getName()).thenReturn("testvm");
+        when(vmRef.getIdString()).thenReturn("testvmid");
+        HostRef ref = mock(HostRef.class);
+        when(ref.getAgentId()).thenReturn("agentId");
+        when(vmRef.getAgent()).thenReturn(ref);
+        
         when(view.getSelectedHostOrVm()).thenReturn(vmRef);
 
         VmInformationController vmInformationController = mock(VmInformationController.class);
@@ -427,11 +433,21 @@
     
     @Test
     public void verifyOpenSameHostVMTab2() {
-
+        
         VmRef vmRef1 = mock(VmRef.class);
         VmRef vmRef2 = mock(VmRef.class);
         when(view.getSelectedHostOrVm()).thenReturn(vmRef1).thenReturn(vmRef1).thenReturn(vmRef2).thenReturn(vmRef1);
 
+        when(vmRef1.getName()).thenReturn("testvm");
+        when(vmRef1.getIdString()).thenReturn("testvmid");
+        HostRef ref = mock(HostRef.class);
+        when(ref.getAgentId()).thenReturn("agentId");
+        when(vmRef1.getAgent()).thenReturn(ref);
+        
+        when(vmRef2.getName()).thenReturn("testvm");
+        when(vmRef2.getIdString()).thenReturn("testvmid");
+        when(vmRef2.getAgent()).thenReturn(ref);
+        
         VmInformationController vmInformationController1 = mock(VmInformationController.class);
         VmInformationController vmInformationController2 = mock(VmInformationController.class);
         
--- a/client/killvm/src/main/java/com/redhat/thermostat/client/killvm/internal/VMKilledListener.java	Tue Sep 04 20:58:27 2012 +0200
+++ b/client/killvm/src/main/java/com/redhat/thermostat/client/killvm/internal/VMKilledListener.java	Tue Sep 04 21:19:29 2012 +0200
@@ -45,29 +45,32 @@
 
 public class VMKilledListener implements RequestResponseListener {
 
-    private static final Logger logger = Logger.getLogger(VMKilledListener.class.getName());
+    private static final Logger logger = Logger
+            .getLogger(VMKilledListener.class.getName());
 
     @Override
     public void fireComplete(Request request, Response response) {
         switch (response.getType()) {
-        case NOOP:  // fall-through
-        case EXCEPTION: // fall-through
-        case NOK: {
-            logger.log(Level.SEVERE, "Unknown response from kill VM request.");
+        case EXCEPTION:
+            logger.log(Level.SEVERE,
+                    "Exception response from kill VM request. Command channel failure?");
             break;
-        }
         case ERROR:
-            logger.log(Level.SEVERE, "Kill request error for VM ID " + request.getParameter("vm-id"));
+            logger.log(Level.SEVERE,
+                    "Kill request error for VM ID "
+                            + request.getParameter("vm-id"));
             break;
-        case PONG:  // fall-through, also OK :)
+        case PONG: // fall-through, also OK :)
         case OK:
             // TODO: Report this to user somehow (notification?)
-            logger.log(Level.INFO, "VM with id " + request.getParameter("vm-id") + " killed on host " + request.getTarget().toString());
+            logger.log(Level.INFO,
+                    "VM with id " + request.getParameter("vm-id")
+                            + " killed on host "
+                            + request.getTarget().toString());
             break;
         default:
             logger.log(Level.WARNING, "Unknown result from KILL VM command.");
             break;
         }
     }
-
 }
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/GraphicsUtils.java	Tue Sep 04 20:58:27 2012 +0200
+++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/GraphicsUtils.java	Tue Sep 04 21:19:29 2012 +0200
@@ -75,6 +75,11 @@
         SwingUtilities2.drawString(component, graphics, string, x, y);
     }
     
+    public void drawString(JComponent component, Graphics2D graphics, String string, Color foreground, int x, int y) {
+        graphics.setColor(foreground);
+        SwingUtilities2.drawString(component, graphics, string, x, y);
+    }
+    
     public FontMetrics getFontMetrics(JComponent component, Font font) {
         return SwingUtilities2.getFontMetrics(component, font);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/StatusBar.java	Tue Sep 04 21:19:29 2012 +0200
@@ -0,0 +1,140 @@
+/*
+ * 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.BorderLayout;
+import java.awt.Dimension;
+import java.beans.Transient;
+
+import javax.swing.ImageIcon;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+
+@SuppressWarnings("serial")
+public class StatusBar extends JPanel {
+
+    // some of this code is inspired by the book
+    // Swing Hacks: Tips & Tools for Building Killer GUIs
+    // By Joshua Marinacci, Chris Adamson
+    // ISBN: 0-596-00907-0
+    // website: http://www.oreilly.com/catalog/swinghks/
+
+    public static final String PRIMARY_STATUS_PROPERTY = "primaryStatus";
+    
+    private Dimension preferredSize;
+    
+    private String primaryStatus = "";
+    private JLabel primaryStatusLabel;
+    private JLabel iconLabel;
+    
+    public StatusBar() {
+        super();
+        setLayout(new BorderLayout(0, 0));
+        
+        primaryStatusLabel = new JLabel(primaryStatus);
+        primaryStatusLabel.setName("primaryStatusLabel");
+        primaryStatusLabel.setFont(getFont().deriveFont(10.0f));
+        primaryStatusLabel.setHorizontalAlignment(JLabel.LEADING);
+        primaryStatusLabel.setVerticalAlignment(JLabel.CENTER);
+
+        add(primaryStatusLabel, BorderLayout.WEST);
+        
+        iconLabel = new JLabel("");
+        ImageIcon grip = new ImageIcon(getClass().getResource("/icons/resize-grip.png"));
+        iconLabel.setIcon(grip);
+
+        iconLabel.setMinimumSize(new Dimension(grip.getIconWidth() + 1, grip.getIconHeight()));
+        iconLabel.setPreferredSize(new Dimension(grip.getIconWidth() + 1, grip.getIconHeight()));
+        iconLabel.setVerticalAlignment(JLabel.BOTTOM);
+
+        add(iconLabel, BorderLayout.EAST);
+        preferredSize = new Dimension(700, grip.getIconHeight() + 5);
+    }
+    
+    @Override
+    @Transient
+    public Dimension getMinimumSize() {
+        if (isMinimumSizeSet()) {
+            return super.getMinimumSize();
+        }
+        return preferredSize;
+    }
+    
+    @Override
+    @Transient
+    public Dimension getPreferredSize() {
+        if (isPreferredSizeSet()) {
+            return super.getPreferredSize();
+        }
+        return preferredSize;
+    }
+    
+    public void setPrimaryStatus(String primaryStatus) {
+        if (primaryStatus == null) throw new NullPointerException();
+        
+        String oldPrimaryStatus = this.primaryStatus;
+        this.primaryStatus = primaryStatus;
+        primaryStatusLabel.setText(" " + primaryStatus);
+        
+        firePropertyChange(PRIMARY_STATUS_PROPERTY, oldPrimaryStatus, this.primaryStatus);
+        repaint();
+    }
+
+    public String getPrimaryStatus() {
+        return primaryStatus;
+    }
+        
+    public static void main(String[] args) {
+        SwingUtilities.invokeLater(new Runnable() {
+            
+            @Override
+            public void run() {
+                JFrame frame = new JFrame();
+                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+                frame.getContentPane().setLayout(new BorderLayout());
+                
+                StatusBar statusBar = new StatusBar();
+                frame.getContentPane().add(statusBar, BorderLayout.SOUTH);
+                
+                frame.setSize(500, 500);
+                frame.setVisible(true);
+            }
+        });
+    }
+}
Binary file client/swing-components/src/main/resources/icons/resize-grip.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing-components/src/main/resources/icons/resize-grip.svg	Tue Sep 04 21:19:29 2012 +0200
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="13"
+   height="13"
+   id="svg17653"
+   version="1.1"
+   inkscape:version="0.48.2 r9819"
+   sodipodi:docname="resize-grip.svg">
+  <defs
+     id="defs17655" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="21.311078"
+     inkscape:cx="-8.2186936"
+     inkscape:cy="8.0008486"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:window-width="1920"
+     inkscape:window-height="1022"
+     inkscape:window-x="0"
+     inkscape:window-y="26"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata17658">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,-3)">
+    <path
+       transform="matrix(0.65777374,0,0,0.65777374,-560.57081,-392.19484)"
+       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
+       sodipodi:ry="1.9003495"
+       sodipodi:rx="1.9003495"
+       sodipodi:cy="617.14966"
+       sodipodi:cx="868.63647"
+       id="path5513"
+       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
+       sodipodi:type="arc" />
+    <path
+       sodipodi:type="arc"
+       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
+       id="path5515"
+       sodipodi:cx="868.63647"
+       sodipodi:cy="617.14966"
+       sodipodi:rx="1.9003495"
+       sodipodi:ry="1.9003495"
+       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
+       transform="matrix(0.65777374,0,0,0.65777374,-563.84354,-392.19484)" />
+    <path
+       sodipodi:type="arc"
+       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
+       id="path5517"
+       sodipodi:cx="868.63647"
+       sodipodi:cy="617.14966"
+       sodipodi:rx="1.9003495"
+       sodipodi:ry="1.9003495"
+       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
+       transform="matrix(0.65777374,0,0,0.65777374,-560.57081,-395.46756)" />
+    <path
+       transform="matrix(0.65777374,0,0,0.65777374,-560.57081,-398.74029)"
+       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
+       sodipodi:ry="1.9003495"
+       sodipodi:rx="1.9003495"
+       sodipodi:cy="617.14966"
+       sodipodi:cx="868.63647"
+       id="path5519"
+       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
+       sodipodi:type="arc" />
+    <path
+       transform="matrix(0.65777374,0,0,0.65777374,-567.11626,-392.19484)"
+       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
+       sodipodi:ry="1.9003495"
+       sodipodi:rx="1.9003495"
+       sodipodi:cy="617.14966"
+       sodipodi:cx="868.63647"
+       id="path5521"
+       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
+       sodipodi:type="arc" />
+    <path
+       transform="matrix(0.65777374,0,0,0.65777374,-563.84354,-395.46756)"
+       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
+       sodipodi:ry="1.9003495"
+       sodipodi:rx="1.9003495"
+       sodipodi:cy="617.14966"
+       sodipodi:cx="868.63647"
+       id="path5523"
+       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
+       sodipodi:type="arc" />
+  </g>
+</svg>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing-components/src/test/java/com/redhat/thermostat/swing/StatusBarTest.java	Tue Sep 04 21:19:29 2012 +0200
@@ -0,0 +1,154 @@
+/*
+ * 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 static org.junit.Assert.*;
+
+import java.awt.BorderLayout;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.concurrent.Semaphore;
+
+import javax.swing.JFrame;
+
+import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
+
+import org.fest.swing.annotation.GUITest;
+import org.fest.swing.annotation.RunsInEDT;
+import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
+import org.fest.swing.edt.GuiActionRunner;
+import org.fest.swing.edt.GuiTask;
+import org.fest.swing.fixture.FrameFixture;
+import org.fest.swing.fixture.JLabelFixture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(CacioFESTRunner.class)
+public class StatusBarTest {
+
+    private JFrame frame;
+    private FrameFixture frameFixture;
+    
+    private StatusBar statusBar;
+    
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+    
+    @Before
+    public void setUp() {
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                frame = new JFrame();
+                frame.getContentPane().setLayout(new BorderLayout());
+                
+                statusBar = new StatusBar();
+                frame.getContentPane().add(statusBar, BorderLayout.SOUTH);
+                
+                frame.setSize(500, 500);
+            }
+        });
+        frameFixture = new FrameFixture(frame);
+    }
+    
+    @After
+    public void tearDown() {
+        frameFixture.cleanUp();
+        frameFixture = null;
+    }
+    
+    @Test
+    @GUITest
+    @RunsInEDT
+    public void testSetPrimaryStatusLabel() throws InterruptedException {
+        frameFixture.show();
+        
+        JLabelFixture labelfixture = frameFixture.label("primaryStatusLabel");
+        labelfixture.requireText("");
+        
+        final Semaphore sem = new Semaphore(0);
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                statusBar.setPrimaryStatus("test");
+                sem.release();
+            }
+        });
+        sem.acquire();
+        
+        // the label has an extra space at the beginning
+        labelfixture.requireText(" test");
+    }
+    
+    @Test
+    @GUITest
+    @RunsInEDT
+    public void testSetPrimaryStatusLabelWithProperty() throws InterruptedException {
+        frameFixture.show();
+        
+        final String[] primaryStatus = new String[2];
+        
+        final Semaphore sem = new Semaphore(2);
+        statusBar.addPropertyChangeListener(StatusBar.PRIMARY_STATUS_PROPERTY,
+                                                      new PropertyChangeListener()
+        {
+            @Override
+            public void propertyChange(PropertyChangeEvent evt) {
+                primaryStatus[0] = (String) evt.getOldValue();
+                primaryStatus[1] = (String) evt.getNewValue();
+                sem.release();
+            }
+        });
+        
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                statusBar.setPrimaryStatus("test");
+                sem.release();
+            }
+        });
+        sem.acquire(2);
+        
+        assertEquals("", primaryStatus[0]);
+        assertEquals("test", primaryStatus[1]);
+    }
+}