Mercurial > hg > release > thermostat-1.0
changeset 1325:2228cf23604c
Restore search for References in the Reference View
review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-November/008749.html
reviewed-by: omajid
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/SearchProvider.java Thu Nov 14 18:17:51 2013 +0100 @@ -0,0 +1,61 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client.ui; + +import com.redhat.thermostat.common.ActionListener; + +/** + * Implementations of this class can be used to notified listeners that a + * search is performed. The search term is used as a payload for the event. + * + * <br /><br /> + * + * The exact type of the search term and conditions upon which the event is + * fired are implementation dependent. + * + * <br /><br /> + * + * This interface is <strong>not</strong> a service. + */ +public interface SearchProvider { + public enum SearchAction { + PERFORM_SEARCH, + } + + public void addSearchListener(ActionListener<SearchAction> listener); + public void removeSearchListener(ActionListener<SearchAction> listener); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/host/swing/HostVmMainLabelDecorator.java Thu Nov 14 18:17:51 2013 +0100 @@ -0,0 +1,53 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client.filter.host.swing; + +import com.redhat.thermostat.client.ui.ReferenceFieldLabelDecorator; +import com.redhat.thermostat.storage.core.Ref; + +public class HostVmMainLabelDecorator implements ReferenceFieldLabelDecorator { + + @Override + public String getLabel(String originalLabel, Ref reference) { + return reference.getName(); + } + + @Override + public int getOrderValue() { + return ORDER_FIRST; + } +}
--- a/client/swing/pom.xml Thu Nov 14 18:17:50 2013 +0100 +++ b/client/swing/pom.xml Thu Nov 14 18:17:51 2013 +0100 @@ -183,6 +183,7 @@ com.redhat.thermostat.client.swing.internal.vmlist.controller, com.redhat.thermostat.client.swing.internal.accordion, com.redhat.thermostat.client.swing.internal.registry.decorator, + com.redhat.thermostat.client.swing.internal.search, </Private-Package> <!-- Do not autogenerate uses clauses in Manifests --> <_nouses>true</_nouses>
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/SearchField.java Thu Nov 14 18:17:50 2013 +0100 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/SearchField.java Thu Nov 14 18:17:51 2013 +0100 @@ -47,7 +47,6 @@ import javax.swing.BorderFactory; import javax.swing.JLabel; -import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; @@ -56,8 +55,7 @@ import com.redhat.thermostat.client.locale.LocaleResources; import com.redhat.thermostat.client.swing.IconResource; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.ActionNotifier; +import com.redhat.thermostat.client.swing.internal.search.BaseSearchProvider; import com.redhat.thermostat.shared.locale.LocalizedString; import com.redhat.thermostat.shared.locale.Translate; @@ -67,19 +65,14 @@ * Similar to other swing components, this component should only be * modified on the swing EDT. */ -public class SearchField extends JPanel { +@SuppressWarnings("serial") +public class SearchField extends BaseSearchProvider { /** For use by tests only */ public static final String VIEW_NAME = "searchField"; - public enum SearchAction { - TEXT_CHANGED, - PERFORM_SEARCH, - } - private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); - private final ActionNotifier<SearchAction> notifier = new ActionNotifier<>(this); private final JTextField searchField = new JTextField(); private final AtomicReference<String> searchText = new AtomicReference<String>(""); @@ -87,7 +80,7 @@ private final AtomicBoolean labelDisplayed = new AtomicBoolean(true); public SearchField() { - super(new BorderLayout()); + setLayout(new BorderLayout()); // TODO move this icon inside the search field JLabel searchIcon = new JLabel(IconResource.SEARCH.getIcon()); @@ -129,7 +122,7 @@ searchText.set(filter); if (!(filter.equals(previousText))) { previousText = filter; - fireViewAction(SearchAction.TEXT_CHANGED); + fireViewAction(SearchAction.PERFORM_SEARCH, searchText.get()); } } } @@ -161,7 +154,7 @@ final java.awt.event.ActionListener searchActionListener = new java.awt.event.ActionListener() { @Override public void actionPerformed(ActionEvent e) { - fireViewAction(SearchAction.PERFORM_SEARCH); + fireViewAction(SearchAction.PERFORM_SEARCH, searchField.getText()); } }; @@ -191,17 +184,5 @@ public void setTooltip(final LocalizedString tooltip) { searchField.setToolTipText(tooltip.getContents()); } - - public void addActionListener(ActionListener<SearchAction> listener) { - notifier.addActionListener(listener); - } - - public void removeActionListener(ActionListener<SearchAction> listener) { - notifier.removeActionListener(listener); - } - - private void fireViewAction(SearchAction action) { - notifier.fireAction(action); - } }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainView.java Thu Nov 14 18:17:50 2013 +0100 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainView.java Thu Nov 14 18:17:51 2013 +0100 @@ -40,6 +40,7 @@ import com.redhat.thermostat.client.core.progress.ProgressNotifier; import com.redhat.thermostat.client.core.views.BasicView; +import com.redhat.thermostat.client.swing.internal.search.ReferenceFieldSearchFilter; import com.redhat.thermostat.client.swing.internal.vmlist.controller.ContextActionController; import com.redhat.thermostat.client.swing.internal.vmlist.controller.HostTreeController; import com.redhat.thermostat.client.ui.MenuAction; @@ -100,5 +101,11 @@ * actions in the UI Client. */ ContextActionController getContextActionController(); + + /** + * Returns the filter used for searching references inside the reference + * tree. + */ + ReferenceFieldSearchFilter getSearchFilter(); }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainWindow.java Thu Nov 14 18:17:50 2013 +0100 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainWindow.java Thu Nov 14 18:17:51 2013 +0100 @@ -80,6 +80,8 @@ import com.redhat.thermostat.client.swing.internal.progress.ProgressNotificationArea; import com.redhat.thermostat.client.swing.internal.progress.SwingProgressNotifier; import com.redhat.thermostat.client.swing.internal.progress.SwingProgressNotifier.PropertyChange; +import com.redhat.thermostat.client.swing.internal.search.ReferenceFieldSearchFilter; +import com.redhat.thermostat.client.swing.internal.search.SearchField; import com.redhat.thermostat.client.swing.internal.sidepane.ExpanderComponent; import com.redhat.thermostat.client.swing.internal.sidepane.ThermostatSidePanel; import com.redhat.thermostat.client.swing.internal.splitpane.ThermostatSplitPane; @@ -120,6 +122,8 @@ private HostTreeController hostTreeController; private ContextActionController contextActionController; + + private ReferenceFieldSearchFilter filter; public MainWindow() { super(); @@ -139,7 +143,7 @@ setupPanels(glassPane); this.setPreferredSize(new Dimension(800, 600)); - + statusBar = new StatusBar(); setupNotificationPane(statusBar, glassPane); @@ -338,6 +342,17 @@ } } }); + + installSearchFiled(); + } + + private void installSearchFiled() { + // install the search field in the sidepane for now + SearchField searchField = new SearchField(); + navigationPanel.getTopPane().add(searchField); + + filter = new ReferenceFieldSearchFilter(searchField, hostTreeController); + hostTreeController.addFilter(filter); } private JPanel createDetailsPanel() { @@ -472,5 +487,10 @@ public ContextActionController getContextActionController() { return contextActionController; } + + @Override + public ReferenceFieldSearchFilter getSearchFilter() { + return filter; + } }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImpl.java Thu Nov 14 18:17:50 2013 +0100 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImpl.java Thu Nov 14 18:17:51 2013 +0100 @@ -59,6 +59,7 @@ import com.redhat.thermostat.client.swing.internal.osgi.ContextActionServiceTracker; import com.redhat.thermostat.client.swing.internal.osgi.InformationServiceTracker; import com.redhat.thermostat.client.swing.internal.registry.decorator.DecoratorRegistryController; +import com.redhat.thermostat.client.swing.internal.search.ReferenceFieldSearchFilter; import com.redhat.thermostat.client.swing.internal.vmlist.controller.ContextActionController; import com.redhat.thermostat.client.swing.internal.vmlist.controller.ContextHandler; import com.redhat.thermostat.client.swing.internal.vmlist.controller.FilterManager; @@ -288,17 +289,20 @@ private void initHostVMTree() { HostTreeController hostController = view.getHostTreeController(); + ReferenceFieldSearchFilter filter = view.getSearchFilter(); // initially fill out with all known host and vms List<HostRef> hosts = networkMonitor.getHosts(new AllPassFilter<HostRef>()); AllPassFilter<VmRef> vmFilter = new AllPassFilter<>(); for (HostRef host : hosts) { hostController.registerHost(host); - + filter.addHost(host); + // get the vm for this host List<VmRef> vms = hostMonitor.getVirtualMachines(host, vmFilter); for (VmRef vm : vms) { hostController.registerVM(vm); + filter.addVM(vm); } } }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/VMMonitorController.java Thu Nov 14 18:17:50 2013 +0100 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/VMMonitorController.java Thu Nov 14 18:17:51 2013 +0100 @@ -36,6 +36,7 @@ package com.redhat.thermostat.client.swing.internal; +import com.redhat.thermostat.client.swing.internal.search.ReferenceFieldSearchFilter; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.storage.core.HostRef; @@ -73,11 +74,13 @@ switch (actionEvent.getActionId()) { case HOST_ADDED: view.getHostTreeController().registerHost(host); + view.getSearchFilter().addHost(host); hostMonitor.addHostChangeListener(host, hostListener); break; case HOST_REMOVED: view.getHostTreeController().updateHostStatus(host); + view.getSearchFilter().removeHost(host); hostMonitor.removeHostChangeListener(host, hostListener); break; @@ -96,11 +99,12 @@ switch (actionEvent.getActionId()) { case VM_ADDED: view.getHostTreeController().registerVM(vm); + view.getSearchFilter().addVM(vm); break; case VM_REMOVED: view.getHostTreeController().updateVMStatus(vm); - + view.getSearchFilter().removeVM(vm); default: break; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/search/BaseSearchProvider.java Thu Nov 14 18:17:51 2013 +0100 @@ -0,0 +1,60 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client.swing.internal.search; + +import javax.swing.JPanel; + +import com.redhat.thermostat.client.ui.SearchProvider; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.ActionNotifier; + +@SuppressWarnings("serial") +public class BaseSearchProvider extends JPanel implements SearchProvider { + private final ActionNotifier<SearchAction> notifier = new ActionNotifier<>(this); + + public void addSearchListener(ActionListener<SearchAction> listener) { + notifier.addActionListener(listener); + } + + public void removeSearchListener(ActionListener<SearchAction> listener) { + notifier.removeActionListener(listener); + } + + protected void fireViewAction(SearchAction action, String text) { + notifier.fireAction(action, text); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/search/ReferenceFieldSearchFilter.java Thu Nov 14 18:17:51 2013 +0100 @@ -0,0 +1,140 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client.swing.internal.search; + +import java.util.concurrent.atomic.AtomicReference; + +import com.redhat.thermostat.client.swing.internal.vmlist.controller.HostTreeController; +import com.redhat.thermostat.client.ui.ReferenceFilter; +import com.redhat.thermostat.client.ui.SearchProvider; +import com.redhat.thermostat.client.ui.SearchProvider.SearchAction; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.storage.core.HostRef; +import com.redhat.thermostat.storage.core.Ref; +import com.redhat.thermostat.storage.core.VmRef; + +/** + * NOTE: This filter is kept private because the Search API is incomplete at + * this point, will be a separate plugin when public search mechanism is in + * place. + */ +public class ReferenceFieldSearchFilter extends ReferenceFilter implements ActionListener<SearchAction> { + private SearchProvider searchProvider; + private AtomicReference<String> searchString; + + private HostTreeController hostTreeController; + + private SearchBackend backend; + + public ReferenceFieldSearchFilter(SearchProvider provider, + HostTreeController hostTreeController) + { + this.searchProvider = provider; + this.searchProvider.addSearchListener(this); + this.searchString = new AtomicReference<>(""); + + this.hostTreeController = hostTreeController; + backend = new SearchBackend(); + } + + /** + * For testing only + */ + void setBackend(SearchBackend backend) { + this.backend = backend; + } + + @Override + public boolean applies(Ref reference) { + boolean applies = false; + + String search = searchString.get(); + if (!search.isEmpty()) { + applies = true; + } + + return applies; + } + + @Override + public boolean matches(Ref reference) { + + String search = searchString.get(); + if (search.isEmpty()) { + return true; + } + + boolean match = backend.match(search, reference); + if (match && (reference instanceof HostRef)) { + // ask to expand this node, in case it's not + hostTreeController.expandNode((HostRef) reference); + } + return match; + } + + @Override + public void actionPerformed(ActionEvent<SearchAction> actionEvent) { + + String oldFilter = searchString.get(); + + String filter = (String) actionEvent.getPayload(); + if (filter != null) { + + if (!oldFilter.equals(filter)) { + searchString.set(filter); + } else { + searchString.set(""); + } + notify(FilterEvent.FILTER_CHANGED); + } + } + + public void addHost(HostRef host) { + backend.addHost(host); + notify(FilterEvent.FILTER_CHANGED); + } + + public void removeHost(HostRef host) {} + + public void addVM(VmRef vm) { + backend.addVM(vm); + notify(FilterEvent.FILTER_CHANGED); + } + + public void removeVM(VmRef vm) {} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/search/SearchBackend.java Thu Nov 14 18:17:51 2013 +0100 @@ -0,0 +1,95 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client.swing.internal.search; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import com.redhat.thermostat.storage.core.HostRef; +import com.redhat.thermostat.storage.core.Ref; +import com.redhat.thermostat.storage.core.VmRef; + +/** + * + */ +class SearchBackend { + + private HashMap<HostRef, Set<VmRef>> hosts; + + public SearchBackend() { + hosts = new HashMap<>(); + } + + public synchronized boolean match(String pattern, Ref reference) { + + boolean match = false; + + String searchString = pattern.toLowerCase(); + + String name = reference.getName().toLowerCase(); + String id = reference.getStringID().toLowerCase(); + + match = name.contains(searchString) || id.contains(searchString); + if (!match && (reference instanceof HostRef)) { + HostRef host = (HostRef) reference; + if (hosts.containsKey(host)) { + for (VmRef vm : hosts.get(host)) { + match = match(searchString, vm); + + // since this is an host, no need to do all, as long as + // we know there's at least one match, this host will + // show up in the reference tree + if (match) { + break; + } + } + } + } + + return match; + } + + public synchronized void addVM(VmRef vm) { + HostRef ref = vm.getHostRef(); + hosts.get(ref).add(vm); + } + + public synchronized void addHost(HostRef host) { + hosts.put(host, new HashSet<VmRef>()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/search/SearchField.java Thu Nov 14 18:17:51 2013 +0100 @@ -0,0 +1,132 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client.swing.internal.search; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Shape; + +import javax.swing.Box; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.border.EmptyBorder; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; + +import com.redhat.thermostat.client.swing.GraphicsUtils; +import com.redhat.thermostat.client.swing.components.FontAwesomeIcon; +import com.redhat.thermostat.client.swing.components.Icon; +import com.redhat.thermostat.client.ui.Palette; + +@SuppressWarnings("serial") +public class SearchField extends BaseSearchProvider { + + private JTextField searchField; + + public SearchField() { + setFocusable(true); + + setLayout(new BorderLayout()); + + final Icon searchIcon = + new FontAwesomeIcon('\uf002', 12, Palette.DARK_GRAY.getColor()); + + searchField = new JTextField(20); + + final JLabel searchLabel = new JLabel(searchIcon); + + JPanel iconPanel = new JPanel(); + iconPanel.setLayout(new BorderLayout()); + iconPanel.add(searchLabel, BorderLayout.CENTER); + iconPanel.add(Box.createRigidArea(new Dimension(2, 5)), BorderLayout.WEST); + + iconPanel.setOpaque(false); + + add(iconPanel, BorderLayout.WEST); + add(searchField, BorderLayout.CENTER); + + searchField.setBackground(Palette.WHITE.getColor()); + searchField.setBorder(new EmptyBorder(0, 5, 0, 0)); + searchField.setForeground(Palette.DARK_GRAY.getColor()); + + searchField.getCaret().setBlinkRate(0); + searchField.setCaretColor(Palette.DARK_GRAY.getColor()); + + setOpaque(false); + setBorder(new EmptyBorder(0, 0, 0, 0)); + + searchField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void changedUpdate(DocumentEvent e) { + Document document = e.getDocument(); + try { + String text = document.getText(0, document.getLength()); + fireViewAction(SearchAction.PERFORM_SEARCH, text); + + } catch (BadLocationException ignore) {} + } + + @Override + public void insertUpdate(DocumentEvent e) { + changedUpdate(e); + } + + @Override + public void removeUpdate(DocumentEvent e) { + changedUpdate(e); + } + }); + } + + @Override + protected void paintComponent(Graphics g) { + GraphicsUtils utils = GraphicsUtils.getInstance(); + Graphics2D graphics = utils.createAAGraphics(g); + + graphics.setPaint(Palette.WHITE.getColor()); + + Shape shape = utils.getRoundShape(getWidth(), getHeight()); + graphics.fill(shape); + + graphics.dispose(); + } +}
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/sidepane/ThermostatSidePanel.java Thu Nov 14 18:17:50 2013 +0100 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/sidepane/ThermostatSidePanel.java Thu Nov 14 18:17:51 2013 +0100 @@ -60,7 +60,6 @@ private JPanel bottom; public ThermostatSidePanel() { - setLayout(new BorderLayout()); top = new TopSidePane(); @@ -93,4 +92,8 @@ bottom.add(comp, contraints); repaint(); } + + public JPanel getTopPane() { + return top; + } }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/sidepane/TopSidePane.java Thu Nov 14 18:17:50 2013 +0100 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/sidepane/TopSidePane.java Thu Nov 14 18:17:51 2013 +0100 @@ -51,7 +51,6 @@ import com.redhat.thermostat.client.swing.components.DebugBorder; import com.redhat.thermostat.client.swing.components.FontAwesomeIcon; import com.redhat.thermostat.client.swing.components.Icon; - import com.redhat.thermostat.client.swing.internal.vmlist.UIDefaultsImpl; @SuppressWarnings("serial")
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/HostTreeController.java Thu Nov 14 18:17:50 2013 +0100 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/HostTreeController.java Thu Nov 14 18:17:51 2013 +0100 @@ -203,8 +203,7 @@ // next filtering step proxyModel.removeHeader(vm.getHostRef()); - } else - if (filter(filters, vm)) { + } else if (filter(filters, vm)) { proxyModel.removeComponent(vm.getHostRef(), vm); } } @@ -343,7 +342,12 @@ private class FilterListener implements ActionListener<Filter.FilterEvent> { @Override public void actionPerformed(ActionEvent<FilterEvent> actionEvent) { - rebuildTree(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + rebuildTree(); + } + }); } } @@ -369,4 +373,13 @@ filter.removeFilterEventListener(filterListener); rebuildTree(); } + + public void expandNode(final HostRef reference) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + accordion.setExpanded(reference, true); + } + }); + } } \ No newline at end of file
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/SearchFieldTest.java Thu Nov 14 18:17:50 2013 +0100 +++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/SearchFieldTest.java Thu Nov 14 18:17:51 2013 +0100 @@ -200,16 +200,16 @@ JTextComponentFixture textBox = frameFixture.textBox(SearchField.VIEW_NAME); - searchField.addActionListener(listener); + searchField.addSearchListener(listener); textBox.enterText(SEARCH_TEXT); verify(listener, times(SEARCH_TEXT.length())).actionPerformed( - new ActionEvent<SearchField.SearchAction>(searchField, SearchField.SearchAction.TEXT_CHANGED)); + new ActionEvent<SearchField.SearchAction>(searchField, SearchField.SearchAction.PERFORM_SEARCH)); textBox.enterText("\n"); - verify(listener).actionPerformed( + verify(listener, times(SEARCH_TEXT.length() + 1)).actionPerformed( new ActionEvent<SearchField.SearchAction>(searchField, SearchField.SearchAction.PERFORM_SEARCH)); }
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/VMMonitorControllerTest.java Thu Nov 14 18:17:50 2013 +0100 +++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/VMMonitorControllerTest.java Thu Nov 14 18:17:51 2013 +0100 @@ -39,15 +39,13 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.times; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import com.redhat.thermostat.client.swing.internal.VMMonitorController.NetworkChangeListener; +import com.redhat.thermostat.client.swing.internal.search.ReferenceFieldSearchFilter; import com.redhat.thermostat.client.swing.internal.vmlist.controller.HostTreeController; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; @@ -62,7 +60,8 @@ private HostMonitor hostMonitor; private MainView view; private HostTreeController treeController; - + private ReferenceFieldSearchFilter searchFilter; + @Before public void setUp() { networkMonitor = mock(NetworkMonitor.class); @@ -70,6 +69,10 @@ view = mock(MainView.class); treeController = mock(HostTreeController.class); when(view.getHostTreeController()).thenReturn(treeController); + + searchFilter = mock(ReferenceFieldSearchFilter.class); + when(view.getSearchFilter()).thenReturn(searchFilter); + } @SuppressWarnings({ "rawtypes", "unchecked" }) @@ -96,7 +99,8 @@ networkListener.actionPerformed(event); verify(treeController).registerHost(host1); - + verify(searchFilter).addHost(host1); + event = new ActionEvent<NetworkMonitor.Action>(networkMonitor, Action.HOST_REMOVED); event.setPayload(host1);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/search/ReferenceFieldSearchFilterTest.java Thu Nov 14 18:17:51 2013 +0100 @@ -0,0 +1,176 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client.swing.internal.search; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; + +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.client.swing.internal.vmlist.controller.HostTreeController; +import com.redhat.thermostat.client.ui.SearchProvider; +import com.redhat.thermostat.client.ui.SearchProvider.SearchAction; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.storage.core.HostRef; +import com.redhat.thermostat.storage.core.Ref; +import com.redhat.thermostat.storage.core.VmRef; + +/** + * + */ +public class ReferenceFieldSearchFilterTest { + + private SearchProvider provider; + private HostTreeController hostTreeController; + + @Before + public void setUp() { + provider = mock(SearchProvider.class); + hostTreeController = mock(HostTreeController.class); + } + + @Test + public void testFilterApplies() { + + ReferenceFieldSearchFilter filter = new ReferenceFieldSearchFilter(provider, hostTreeController); + assertFalse(filter.applies(mock(Ref.class))); + + ActionEvent<SearchAction> actionEvent = + new ActionEvent<SearchProvider.SearchAction>(this, SearchAction.PERFORM_SEARCH); + actionEvent.setPayload("some search string"); + + filter.actionPerformed(actionEvent); + + assertTrue(filter.applies(mock(Ref.class))); + } + + @Test + public void testSearchMatchFilterInactive() { + + HostRef host0 = new HostRef("h0", "host#0"); + VmRef vm0 = new VmRef(host0, "v0", 0, "vm#0"); + + ReferenceFieldSearchFilter filter = new ReferenceFieldSearchFilter(provider, hostTreeController); + + assertTrue(filter.matches(host0)); + assertTrue(filter.matches(vm0)); + } + + @Test + public void testSearchHandledCorrectly() { + + HostRef host0 = new HostRef("h0", "host#0"); + VmRef vm0 = new VmRef(host0, "v0", 0, "vm#0"); + + SearchBackend backend = mock(SearchBackend.class); + + ReferenceFieldSearchFilter filter = new ReferenceFieldSearchFilter(provider, hostTreeController); + filter.setBackend(backend); + + ActionEvent<SearchAction> actionEvent = + new ActionEvent<SearchProvider.SearchAction>(this, SearchAction.PERFORM_SEARCH); + actionEvent.setPayload("some search string"); + + filter.actionPerformed(actionEvent); + + filter.matches(host0); + + verify(backend).match("some search string", host0); + + filter.matches(vm0); + + verify(backend).match("some search string", vm0); + } + + @Test + public void testTreeExpandedForHostOnly() { + + HostRef host0 = new HostRef("h0", "host#0"); + VmRef vm0 = new VmRef(host0, "v0", 0, "vm#0"); + + SearchBackend backend = mock(SearchBackend.class); + when(backend.match(any(String.class), any(HostRef.class))).thenReturn(true); + when(backend.match(any(String.class), any(VmRef.class))).thenReturn(true); + + ReferenceFieldSearchFilter filter = new ReferenceFieldSearchFilter(provider, hostTreeController); + filter.setBackend(backend); + + ActionEvent<SearchAction> actionEvent = + new ActionEvent<SearchProvider.SearchAction>(this, SearchAction.PERFORM_SEARCH); + actionEvent.setPayload("some search string"); + + filter.actionPerformed(actionEvent); + + boolean result = filter.matches(host0); + assertTrue(result); + + verify(backend).match("some search string", host0); + verify(hostTreeController).expandNode(host0); + + result = filter.matches(vm0); + assertTrue(result); + + verify(backend).match("some search string", vm0); + verifyNoMoreInteractions(hostTreeController); + } + + @Test + public void testAddReferenceProxiedToBackend() { + + HostRef host0 = new HostRef("h0", "host#0"); + VmRef vm0 = new VmRef(host0, "v0", 0, "vm#0"); + + SearchBackend backend = mock(SearchBackend.class); + + ReferenceFieldSearchFilter filter = new ReferenceFieldSearchFilter(provider, hostTreeController); + filter.setBackend(backend); + + filter.addHost(host0); + verify(backend).addHost(host0); + + filter.addVM(vm0); + verify(backend).addVM(vm0); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/search/SearchBackendTest.java Thu Nov 14 18:17:51 2013 +0100 @@ -0,0 +1,143 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client.swing.internal.search; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; + +import org.junit.Test; + +import com.redhat.thermostat.storage.core.HostRef; +import com.redhat.thermostat.storage.core.VmRef; + +/** + * + */ +public class SearchBackendTest { + + @Test + public void testSearchUnMatch() { + + SearchBackend backend = new SearchBackend(); + + HostRef host0 = new HostRef("0", "some weird host"); + + boolean result = backend.match("some host", host0); + assertFalse(result); + } + + @Test + public void testSearchMatch0() { + + SearchBackend backend = new SearchBackend(); + + HostRef host0 = new HostRef("0", "some host"); + + backend.addHost(host0); + + boolean result = backend.match("some host", host0); + assertTrue(result); + } + + @Test + public void testSearchMatch1() { + SearchBackend backend = new SearchBackend(); + + HostRef host0 = new HostRef("host0", "some weird host"); + HostRef host1 = new HostRef("host1", "some host"); + + VmRef vm0 = new VmRef(host0, "vm0", 0, "some vm"); + VmRef vm1 = new VmRef(host1, "vm1", 1, "some other vm"); + + backend.addHost(host0); + backend.addHost(host1); + backend.addVM(vm0); + backend.addVM(vm1); + + boolean result = backend.match("some host", host1); + assertTrue(result); + + result = backend.match("some other vm", host1); + assertTrue(result); + } + + @Test + public void testSearchUnMatchWithParent() { + + SearchBackend backend = new SearchBackend(); + + HostRef host0 = new HostRef("host0", "some weird host"); + HostRef host1 = new HostRef("host1", "some host"); + + VmRef vm0 = new VmRef(host0, "vm0", 0, "some vm"); + VmRef vm1 = new VmRef(host1, "vm1", 1, "some other vm"); + + backend.addHost(host0); + backend.addHost(host1); + backend.addVM(vm0); + backend.addVM(vm1); + + boolean result = backend.match("somehost", host1); + assertFalse(result); + + result = backend.match("some vm", host1); + assertFalse(result); + } + + @Test + public void testSearchMatch2() { + SearchBackend backend = new SearchBackend(); + + HostRef host0 = new HostRef("host0", "some weird host"); + HostRef host1 = new HostRef("host1", "some host"); + HostRef host2 = new HostRef("host2", "some host"); + + VmRef vm0 = new VmRef(host0, "vm0", 0, "some vm"); + VmRef vm1 = new VmRef(host1, "vm1", 1, "some other vm"); + + backend.addHost(host0); + backend.addHost(host1); + backend.addVM(vm0); + backend.addVM(vm1); + + boolean result = backend.match("some host", host2); + assertTrue(result); + + result = backend.match("some other vm", host2); + assertFalse(result); + } +}
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/HostTreeControllerTest.java Thu Nov 14 18:17:50 2013 +0100 +++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/HostTreeControllerTest.java Thu Nov 14 18:17:51 2013 +0100 @@ -196,7 +196,8 @@ filter1.toggle(); waitForSwing(); - + waitForSwing(); + headers = proxyModel.getHeaders(); assertEquals(2, headers.size()); assertTrue(headers.contains(host0)); @@ -239,6 +240,7 @@ filter2.toggle(); waitForSwing(); + waitForSwing(); components = proxyModel.getComponents(host0); assertEquals(1, components.size());
--- a/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectDetailsPanel.java Thu Nov 14 18:17:50 2013 +0100 +++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectDetailsPanel.java Thu Nov 14 18:17:51 2013 +0100 @@ -57,7 +57,7 @@ import com.redhat.thermostat.client.swing.EdtHelper; import com.redhat.thermostat.client.swing.SwingComponent; import com.redhat.thermostat.client.swing.components.SearchField; -import com.redhat.thermostat.client.swing.components.SearchField.SearchAction; +import com.redhat.thermostat.client.ui.SearchProvider.SearchAction; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionNotifier; @@ -70,6 +70,7 @@ import javax.swing.LayoutStyle.ComponentPlacement; import javax.swing.JScrollPane; import javax.swing.JTextPane; + import java.awt.BorderLayout; import java.awt.Component; import java.awt.event.MouseAdapter; @@ -173,11 +174,11 @@ .addContainerGap()) ); - searchField.addActionListener(new ActionListener<SearchAction>() { + searchField.addSearchListener(new ActionListener<SearchAction>() { @Override public void actionPerformed(ActionEvent<SearchAction> actionEvent) { switch (actionEvent.getActionId()) { - case TEXT_CHANGED: + case PERFORM_SEARCH: notifier.fireAction(ObjectAction.SEARCH); break; default: