Mercurial > hg > release > thermostat-0.11
changeset 128:9d043bbbdbcd
Move view related code from MainWindow controller to view class.
author | Roman Kennke <rkennke@redhat.com> |
---|---|
date | Wed, 21 Mar 2012 20:52:33 +0100 |
parents | 9ae036f42ea8 |
children | 17916c4207d3 |
files | client/src/main/java/com/redhat/thermostat/client/HostsVMsLoader.java client/src/main/java/com/redhat/thermostat/client/MainWindowFacade.java client/src/main/java/com/redhat/thermostat/client/MainWindowFacadeImpl.java client/src/main/java/com/redhat/thermostat/client/ui/MainWindow.java client/src/test/java/com/redhat/thermostat/client/ui/MainWindowTest.java |
diffstat | 5 files changed, 211 insertions(+), 177 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/src/main/java/com/redhat/thermostat/client/HostsVMsLoader.java Wed Mar 21 20:52:33 2012 +0100 @@ -0,0 +1,51 @@ +/* + * 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; + +import java.util.Collection; + +import com.redhat.thermostat.common.dao.HostRef; +import com.redhat.thermostat.common.dao.VmRef; + +/** + * Provides a way to load the current hosts and VMs. + */ +public interface HostsVMsLoader { + + Collection<HostRef> getHosts(); + Collection<VmRef> getVMs(HostRef host); +}
--- a/client/src/main/java/com/redhat/thermostat/client/MainWindowFacade.java Wed Mar 21 17:14:53 2012 +0100 +++ b/client/src/main/java/com/redhat/thermostat/client/MainWindowFacade.java Wed Mar 21 20:52:33 2012 +0100 @@ -36,26 +36,16 @@ package com.redhat.thermostat.client; -import javax.swing.tree.TreeModel; - import com.redhat.thermostat.client.ui.MainWindow; -import com.redhat.thermostat.common.dao.HostRef; -import com.redhat.thermostat.common.dao.VmRef; public interface MainWindowFacade extends AsyncUiFacade { - public HostRef[] getHosts(); - - public VmRef[] getVms(HostRef ref); - - public TreeModel getHostVmTree(); - public void setHostVmTreeFilter(String filter); /** * TODO: This method is only here temporarily until we inversed the dependency between the MainWindow * and MainWindowFacadeImpl classes. */ - public void initListeners(MainWindow mainWindow); + public void initView(MainWindow mainWindow); }
--- a/client/src/main/java/com/redhat/thermostat/client/MainWindowFacadeImpl.java Wed Mar 21 17:14:53 2012 +0100 +++ b/client/src/main/java/com/redhat/thermostat/client/MainWindowFacadeImpl.java Wed Mar 21 20:52:33 2012 +0100 @@ -36,42 +36,28 @@ package com.redhat.thermostat.client; -import static com.redhat.thermostat.client.locale.Translate.localize; - import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.io.PrintStream; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; +import java.util.Collection; import java.util.List; import java.util.Timer; import java.util.TimerTask; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; -import javax.swing.SwingWorker; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreeModel; -import javax.swing.tree.TreeNode; - import com.mongodb.BasicDBObject; import com.mongodb.DB; import com.mongodb.DBCollection; import com.mongodb.DBCursor; import com.mongodb.DBObject; -import com.redhat.thermostat.client.locale.LocaleResources; import com.redhat.thermostat.client.ui.MainWindow; import com.redhat.thermostat.common.dao.HostRef; -import com.redhat.thermostat.common.dao.Ref; import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.common.utils.StringUtils; -public class MainWindowFacadeImpl implements MainWindowFacade { +public class MainWindowFacadeImpl implements MainWindowFacade, HostsVMsLoader { private static final Logger logger = LoggingUtils.getLogger(MainWindowFacadeImpl.class); @@ -79,13 +65,11 @@ private final DBCollection hostInfoCollection; private final DBCollection vmInfoCollection; - private final DefaultMutableTreeNode publishedRoot = - new DefaultMutableTreeNode(localize(LocaleResources.MAIN_WINDOW_TREE_ROOT_NAME)); - private final DefaultTreeModel publishedTreeModel = new DefaultTreeModel(publishedRoot); + private final Timer backgroundUpdater = new Timer(); - private String filterText; + private MainWindow view; - private final Timer backgroundUpdater = new Timer(); + private String filter; public MainWindowFacadeImpl(DB db) { this.agentConfigCollection = db.getCollection("agent-config"); @@ -109,7 +93,7 @@ } @Override - public HostRef[] getHosts() { + public Collection<HostRef> getHosts() { List<HostRef> hostRefs = new ArrayList<HostRef>(); DBCursor cursor = agentConfigCollection.find(); @@ -124,11 +108,11 @@ } } logger.log(Level.FINER, "found " + hostRefs.size() + " connected agents"); - return hostRefs.toArray(new HostRef[0]); + return hostRefs; } @Override - public VmRef[] getVms(HostRef hostRef) { + public Collection<VmRef> getVMs(HostRef hostRef) { List<VmRef> vmRefs = new ArrayList<VmRef>(); DBCursor cursor = vmInfoCollection.find(new BasicDBObject("agent-id", hostRef.getAgentId())); while (cursor.hasNext()) { @@ -140,149 +124,22 @@ vmRefs.add(ref); } - return vmRefs.toArray(new VmRef[0]); - } - - @Override - public TreeModel getHostVmTree() { - return publishedTreeModel; - } - - private Ref[] getChildren(Ref parent) { - if (parent == null) { - return getHosts(); - } else if (parent instanceof HostRef) { - HostRef host = (HostRef) parent; - return getVms(host); - } - return new Ref[0]; + return vmRefs; } @Override public void setHostVmTreeFilter(String filter) { - this.filterText = filter; + this.filter = filter; doUpdateTreeAsync(); } public void doUpdateTreeAsync() { - BackgroundTreeModelWorker worker = new BackgroundTreeModelWorker(this, publishedTreeModel, publishedRoot); - worker.execute(); - } - - /** - * Updates a TreeModel in the background in an Swing EDT-safe manner. - */ - private static class BackgroundTreeModelWorker extends SwingWorker<DefaultMutableTreeNode, Void> { - - private final DefaultTreeModel treeModel; - private MainWindowFacadeImpl facade; - private DefaultMutableTreeNode treeRoot; - - public BackgroundTreeModelWorker(MainWindowFacadeImpl facade, DefaultTreeModel model, DefaultMutableTreeNode root) { - this.facade = facade; - this.treeModel = model; - this.treeRoot = root; - } - - @Override - protected DefaultMutableTreeNode doInBackground() throws Exception { - DefaultMutableTreeNode root = new DefaultMutableTreeNode(); - List<HostRef> hostsInRemoteModel = Arrays.asList(facade.getHosts()); - buildSubTree(root, hostsInRemoteModel, facade.filterText); - return root; - } - - private boolean buildSubTree(DefaultMutableTreeNode parent, List<? extends Ref> objectsInRemoteModel, String filter) { - boolean subTreeMatches = false; - for (Ref inRemoteModel : objectsInRemoteModel) { - DefaultMutableTreeNode inTreeNode = new DefaultMutableTreeNode(inRemoteModel); - - boolean shouldInsert = false; - if (filter == null || inRemoteModel.matches(filter)) { - shouldInsert = true; - } - - List<Ref> children = Arrays.asList(facade.getChildren(inRemoteModel)); - boolean subtreeResult = buildSubTree(inTreeNode, children, filter); - if (subtreeResult) { - shouldInsert = true; - } - - if (shouldInsert) { - parent.add(inTreeNode); - subTreeMatches = true; - } - } - return subTreeMatches; - } - - @Override - protected void done() { - DefaultMutableTreeNode sourceRoot; - try { - sourceRoot = get(); - syncTree(sourceRoot, treeModel, treeRoot); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { - e.printStackTrace(); - } - } - - private void syncTree(DefaultMutableTreeNode sourceRoot, DefaultTreeModel targetModel, DefaultMutableTreeNode targetNode) { - @SuppressWarnings("unchecked") // We know what we put into these trees. - List<DefaultMutableTreeNode> sourceChildren = Collections.list(sourceRoot.children()); - @SuppressWarnings("unchecked") - List<DefaultMutableTreeNode> targetChildren = Collections.list(targetNode.children()); - for (DefaultMutableTreeNode sourceChild : sourceChildren) { - Ref sourceRef = (Ref) sourceChild.getUserObject(); - DefaultMutableTreeNode targetChild = null; - for (DefaultMutableTreeNode aChild : targetChildren) { - Ref targetRef = (Ref) aChild.getUserObject(); - if (targetRef.equals(sourceRef)) { - targetChild = aChild; - break; - } - } - - if (targetChild == null) { - targetChild = new DefaultMutableTreeNode(sourceRef); - targetModel.insertNodeInto(targetChild, targetNode, targetNode.getChildCount()); - } - - syncTree(sourceChild, targetModel, targetChild); - } - - for (DefaultMutableTreeNode targetChild : targetChildren) { - Ref targetRef = (Ref) targetChild.getUserObject(); - boolean matchFound = false; - for (DefaultMutableTreeNode sourceChild : sourceChildren) { - Ref sourceRef = (Ref) sourceChild.getUserObject(); - if (targetRef.equals(sourceRef)) { - matchFound = true; - break; - } - } - - if (!matchFound) { - targetModel.removeNodeFromParent(targetChild); - } - } - } - } - - @SuppressWarnings("unused") // Used for debugging but not in production code. - private static void printTree(PrintStream out, TreeNode node, int depth) { - out.println(StringUtils.repeat(" ", depth) + node.toString()); - @SuppressWarnings("unchecked") - List<TreeNode> children = Collections.list(node.children()); - for (TreeNode child : children) { - printTree(out, child, depth + 1); - } + view.updateTree(filter, this); } @Override - public void initListeners(MainWindow mainWindow) { + public void initView(MainWindow mainWindow) { + this.view = mainWindow; mainWindow.addViewPropertyListener(new PropertyChangeListener() { @Override
--- a/client/src/main/java/com/redhat/thermostat/client/ui/MainWindow.java Wed Mar 21 17:14:53 2012 +0100 +++ b/client/src/main/java/com/redhat/thermostat/client/ui/MainWindow.java Wed Mar 21 20:52:33 2012 +0100 @@ -51,6 +51,11 @@ import java.awt.event.WindowEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; +import java.io.PrintStream; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; import javax.swing.BorderFactory; import javax.swing.JFrame; @@ -65,6 +70,7 @@ import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.KeyStroke; +import javax.swing.SwingWorker; import javax.swing.ToolTipManager; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; @@ -78,18 +84,136 @@ import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeModel; +import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import com.redhat.thermostat.client.ApplicationInfo; +import com.redhat.thermostat.client.HostsVMsLoader; import com.redhat.thermostat.client.MainWindowFacade; import com.redhat.thermostat.client.UiFacadeFactory; import com.redhat.thermostat.client.locale.LocaleResources; import com.redhat.thermostat.common.dao.HostRef; +import com.redhat.thermostat.common.dao.Ref; import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.common.utils.StringUtils; public class MainWindow extends JFrame { + /** + * Updates a TreeModel in the background in an Swing EDT-safe manner. + */ + private static class BackgroundTreeModelWorker extends SwingWorker<DefaultMutableTreeNode, Void> { + + private final DefaultTreeModel treeModel; + private DefaultMutableTreeNode treeRoot; + private String filterText; + private HostsVMsLoader hostsVMsLoader; + + public BackgroundTreeModelWorker(DefaultTreeModel model, DefaultMutableTreeNode root, String filterText, HostsVMsLoader hostsVMsLoader) { + this.filterText = filterText; + this.treeModel = model; + this.treeRoot = root; + this.hostsVMsLoader = hostsVMsLoader; + } + + @Override + protected DefaultMutableTreeNode doInBackground() throws Exception { + DefaultMutableTreeNode root = new DefaultMutableTreeNode(); + Collection<HostRef> hostsInRemoteModel = hostsVMsLoader.getHosts(); + buildSubTree(root, hostsInRemoteModel, filterText); + return root; + } + + private boolean buildSubTree(DefaultMutableTreeNode parent, Collection<? extends Ref> objectsInRemoteModel, String filter) { + boolean subTreeMatches = false; + for (Ref inRemoteModel : objectsInRemoteModel) { + DefaultMutableTreeNode inTreeNode = new DefaultMutableTreeNode(inRemoteModel); + + boolean shouldInsert = false; + if (filter == null || inRemoteModel.matches(filter)) { + shouldInsert = true; + } + + Collection<? extends Ref> children = getChildren(inRemoteModel); + boolean subtreeResult = buildSubTree(inTreeNode, children, filter); + if (subtreeResult) { + shouldInsert = true; + } + + if (shouldInsert) { + parent.add(inTreeNode); + subTreeMatches = true; + } + } + return subTreeMatches; + } + + @Override + protected void done() { + DefaultMutableTreeNode sourceRoot; + try { + sourceRoot = get(); + syncTree(sourceRoot, treeModel, treeRoot); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + } + + private Collection<? extends Ref> getChildren(Ref parent) { + if (parent == null) { + return hostsVMsLoader.getHosts(); + } else if (parent instanceof HostRef) { + HostRef host = (HostRef) parent; + return hostsVMsLoader.getVMs(host); + } + return Collections.emptyList(); + } + + private void syncTree(DefaultMutableTreeNode sourceRoot, DefaultTreeModel targetModel, DefaultMutableTreeNode targetNode) { + @SuppressWarnings("unchecked") // We know what we put into these trees. + List<DefaultMutableTreeNode> sourceChildren = Collections.list(sourceRoot.children()); + @SuppressWarnings("unchecked") + List<DefaultMutableTreeNode> targetChildren = Collections.list(targetNode.children()); + for (DefaultMutableTreeNode sourceChild : sourceChildren) { + Ref sourceRef = (Ref) sourceChild.getUserObject(); + DefaultMutableTreeNode targetChild = null; + for (DefaultMutableTreeNode aChild : targetChildren) { + Ref targetRef = (Ref) aChild.getUserObject(); + if (targetRef.equals(sourceRef)) { + targetChild = aChild; + break; + } + } + + if (targetChild == null) { + targetChild = new DefaultMutableTreeNode(sourceRef); + targetModel.insertNodeInto(targetChild, targetNode, targetNode.getChildCount()); + } + + syncTree(sourceChild, targetModel, targetChild); + } + + for (DefaultMutableTreeNode targetChild : targetChildren) { + Ref targetRef = (Ref) targetChild.getUserObject(); + boolean matchFound = false; + for (DefaultMutableTreeNode sourceChild : sourceChildren) { + Ref sourceRef = (Ref) sourceChild.getUserObject(); + if (targetRef.equals(sourceRef)) { + matchFound = true; + break; + } + } + + if (!matchFound) { + targetModel.removeNodeFromParent(targetChild); + } + } + } + } + private static final long serialVersionUID = 5608972421496808177L; // TODO: When we break out a view interface, this constant needs to go there. @@ -109,6 +233,10 @@ private PropertyChangeSupport viewPropertySupport = new PropertyChangeSupport(this); + private final DefaultMutableTreeNode publishedRoot = + new DefaultMutableTreeNode(localize(LocaleResources.MAIN_WINDOW_TREE_ROOT_NAME)); + private final DefaultTreeModel publishedTreeModel = new DefaultTreeModel(publishedRoot); + public MainWindow(UiFacadeFactory facadeFactory) { super(); @@ -117,12 +245,12 @@ this.facadeFactory = facadeFactory; this.facade = facadeFactory.getMainWindow(); - facade.initListeners(this); + facade.initView(this); shutdownAction = new ShutdownClient(facade, this); searchField = new JTextField(); searchField.setName("hostVMTreeFilter"); - TreeModel model = facade.getHostVmTree(); + TreeModel model = publishedTreeModel; agentVmTree = new JTree(model); model.addTreeModelListener(new KeepRootExpandedListener(agentVmTree)); agentVmTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); @@ -401,4 +529,20 @@ private void fireViewPropertyChange(String propertyName, Object oldValue, Object newValue) { viewPropertySupport.firePropertyChange(propertyName, oldValue, newValue); } + + public void updateTree(String filter, HostsVMsLoader hostsVMsLoader) { + BackgroundTreeModelWorker worker = new BackgroundTreeModelWorker(publishedTreeModel, publishedRoot, filter, hostsVMsLoader); + worker.execute(); + } + + @SuppressWarnings("unused") // Used for debugging but not in production code. + private static void printTree(PrintStream out, TreeNode node, int depth) { + out.println(StringUtils.repeat(" ", depth) + node.toString()); + @SuppressWarnings("unchecked") + List<TreeNode> children = Collections.list(node.children()); + for (TreeNode child : children) { + printTree(out, child, depth + 1); + } + } + }
--- a/client/src/test/java/com/redhat/thermostat/client/ui/MainWindowTest.java Wed Mar 21 17:14:53 2012 +0100 +++ b/client/src/test/java/com/redhat/thermostat/client/ui/MainWindowTest.java Wed Mar 21 20:52:33 2012 +0100 @@ -44,11 +44,6 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreeModel; -import javax.swing.tree.TreeNode; - import org.apache.commons.lang3.ObjectUtils; import org.fest.swing.fixture.FrameFixture; import org.fest.swing.fixture.JTextComponentFixture; @@ -94,9 +89,6 @@ @Test public void testHostVMTreeFilterPropertySupport() { MainWindowFacade mainWindowFacade = mock(MainWindowFacade.class); - TreeNode root = new DefaultMutableTreeNode(); - TreeModel treeModel = new DefaultTreeModel(root); - when(mainWindowFacade.getHostVmTree()).thenReturn(treeModel); SummaryPanelFacade summaryPanelFacade = mock(SummaryPanelFacade.class); when(summaryPanelFacade.getTotalConnectedAgents()).thenReturn(new ChangeableText("totalConnectedAgents"));