/* * RHQ Management Platform * Copyright (C) 2005-2011 Red Hat, Inc. * All rights reserved. * * This program 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 version 2 of the License. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.coregui.client.components.view; import java.util.EnumSet; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import com.smartgwt.client.types.Autofit; import com.smartgwt.client.types.SelectionStyle; import com.smartgwt.client.types.VisibilityMode; import com.smartgwt.client.widgets.Canvas; import com.smartgwt.client.widgets.grid.events.CellClickEvent; import com.smartgwt.client.widgets.grid.events.CellClickHandler; import com.smartgwt.client.widgets.layout.SectionStack; import com.smartgwt.client.widgets.layout.SectionStackSection; import com.smartgwt.client.widgets.tree.Tree; import com.smartgwt.client.widgets.tree.TreeGrid; import com.smartgwt.client.widgets.tree.TreeNode; import org.rhq.core.domain.authz.Permission; import org.rhq.coregui.client.BookmarkableView; import org.rhq.coregui.client.CoreGUI; import org.rhq.coregui.client.InitializableView; import org.rhq.coregui.client.PermissionsLoadedListener; import org.rhq.coregui.client.PermissionsLoader; import org.rhq.coregui.client.RefreshableView; import org.rhq.coregui.client.ViewId; import org.rhq.coregui.client.ViewPath; import org.rhq.coregui.client.components.TitleBar; import org.rhq.coregui.client.components.tree.EnhancedTreeNode; import org.rhq.coregui.client.util.Log; import org.rhq.coregui.client.util.enhanced.EnhancedHLayout; import org.rhq.coregui.client.util.enhanced.EnhancedVLayout; /** * The base class for the various top-level views which have a sectioned navigation menu on the left side and a content * pane on the right side. * * @author Greg Hinkle * @author Ian Springer * @author Jay Shaughnessy */ public abstract class AbstractSectionedLeftNavigationView extends EnhancedHLayout implements BookmarkableView, InitializableView { private String viewId; private boolean initialized; private ViewId currentSectionViewId; private ViewId currentPageViewId; private SectionStack sectionStack; private Canvas contentCanvas; private Canvas currentContent; private Map<String, TreeGrid> treeGrids = new LinkedHashMap<String, TreeGrid>(); private Map<String, NavigationSection> sectionsByName; // Capture the user's global permissions for use by any dashboard or portlet that may need it for rendering. private Set<Permission> globalPermissions = EnumSet.noneOf(Permission.class); public AbstractSectionedLeftNavigationView(String viewId) { super(); this.viewId = viewId; } @Override protected void onInit() { super.onInit(); setWidth100(); setHeight100(); contentCanvas = new Canvas(); contentCanvas.setWidth("*"); contentCanvas.setHeight100(); sectionStack = new SectionStack(); sectionStack.setShowResizeBar(true); sectionStack.setCanResizeSections(true); sectionStack.setVisibilityMode(VisibilityMode.MULTIPLE); sectionStack.setWidth(250); sectionStack.setHeight100(); new PermissionsLoader().loadExplicitGlobalPermissions(new PermissionsLoadedListener() { public void onPermissionsLoaded(Set<Permission> permissions) { globalPermissions = (permissions != null) ? permissions : EnumSet.noneOf(Permission.class); List<NavigationSection> sections = getNavigationSections(); sectionsByName = new HashMap<String, NavigationSection>(sections.size()); for (NavigationSection section : sections) { TreeGrid treeGrid = buildTreeGridForSection(section); addSection(treeGrid); treeGrid.getTree().openAll(); sectionsByName.put(section.getName(), section); } addMember(sectionStack); addMember(contentCanvas); initialized = true; } }); } @Override public boolean isInitialized() { return this.initialized; } protected abstract Canvas defaultView(); protected abstract List<NavigationSection> getNavigationSections(); private TreeGrid buildTreeGridForSection(NavigationSection navigationSection) { final TreeGrid treeGrid = new TreeGrid(); treeGrid.setLeaveScrollbarGap(false); treeGrid.setShowHeader(false); treeGrid.setSelectionType(SelectionStyle.SINGLE); treeGrid.setHeight(50); // treeGrid.setExtraSpace(5); treeGrid.addStyleName("noOutline"); treeGrid.setAutoFitData(Autofit.VERTICAL); List<NavigationItem> navigationItems = navigationSection.getNavigationItems(); TreeNode[] treeNodes = new TreeNode[navigationItems.size()]; for (int i = 0, navigationItemsSize = navigationItems.size(); i < navigationItemsSize; i++) { NavigationItem item = navigationItems.get(i); final TreeNode treeNode = new EnhancedTreeNode(item.getName(), item.getTitle()); treeNode.setIcon(item.getIcon()); treeNode.setEnabled(item.isEnabled()); treeNodes[i] = treeNode; } TreeNode rootNode = new EnhancedTreeNode(navigationSection.getName(), navigationSection.getTitle(), treeNodes); Tree tree = new Tree(); tree.setRoot(rootNode); treeGrid.setData(tree); return treeGrid; } private void addSection(final TreeGrid treeGrid) { final String sectionName = treeGrid.getTree().getRoot().getName(); final String sectionTitle = treeGrid.getTree().getRoot().getTitle(); this.treeGrids.put(sectionName, treeGrid); treeGrid.addCellClickHandler(new CellClickHandler() { @Override public void onCellClick(CellClickEvent event) { // We use cell click as opposed to selected changed handler // because we want to be able to refresh even if clicking // on an already selected node. TreeNode selectedRecord = (TreeNode) treeGrid.getSelectedRecord(); if (selectedRecord != null) { String pageName = selectedRecord.getName(); String viewPath = viewId + "/" + sectionName + "/" + pageName; CoreGUI.goToView(viewPath); } } }); SectionStackSection section = new SectionStackSection(sectionTitle); section.setResizeable(true); section.setExpanded(true); section.addItem(treeGrid); this.sectionStack.addSection(section); } public void destroyCurrentContent() { // A call to destroy (e.g. certain IFrames/FullHTMLPane) can actually remove multiple children of the // contentCanvas. As such, we need to query for the children after each destroy to ensure only valid children // are in the array. Note that we need to make sure we do this destroy before we create the new content if (contentCanvas != null) { Canvas[] children; while ((children = contentCanvas.getChildren()).length > 0) { children[0].destroy(); } } } public void setContent(Canvas newContent) { currentContent = newContent; if (newContent instanceof HasViewName) { EnhancedVLayout decoratedContent = decorateWithTitleBar(((HasViewName) newContent).getViewName(), newContent); contentCanvas.addChild(decoratedContent); } else { contentCanvas.addChild(newContent); } contentCanvas.markForRedraw(); } private void renderContentView(ViewPath viewPath) { this.currentSectionViewId = viewPath.getCurrent(); this.currentPageViewId = viewPath.getNext(); String sectionName = this.currentSectionViewId.getPath(); String pageName = this.currentPageViewId.getPath(); NavigationSection section = this.sectionsByName.get(sectionName); if (section == null) { throw new IllegalStateException("Invalid section: " + sectionName); } NavigationItem item = section.getNavigationItem(pageName); if (item == null) { throw new IllegalStateException("Invalid page: " + pageName); } if (item.isRefreshRequired()) { this.currentPageViewId = null; } // When changing sections, make sure the previous section's selection is deselected. selectSectionPageTreeGridNode(sectionName, pageName); // Only update the content pane if the item has an associated view factory. ViewFactory viewFactory = item.getViewFactory(); if (viewFactory != null) { destroyCurrentContent(); Canvas content = viewFactory.createView(); if (content != null) { setContent(content); if (content instanceof BookmarkableView) { ((BookmarkableView) content).renderView(viewPath.next().next()); } } } } public void renderView(ViewPath viewPath) { if (!viewPath.isCurrent(currentSectionViewId) || !viewPath.isNext(currentPageViewId)) { if (viewPath.isEnd()) { // Display default view - note that defaultView() will create new content, so we have to destroy the old, current content destroyCurrentContent(); setContent(defaultView()); initSectionPageTreeGrids(); } else { renderContentView(viewPath); } } else { if (this.currentContent instanceof BookmarkableView) { ((BookmarkableView) this.currentContent).renderView(viewPath.next().next()); } else if (this.currentContent instanceof RefreshableView && this.currentContent.isDrawn()) { // Refresh the data on the content pane, so it's not stale. Log.debug("Refreshing data for [" + this.currentContent.getClass().getName() + "]..."); ((RefreshableView) this.currentContent).refresh(); } } } private void initSectionPageTreeGrids() { for (String name : treeGrids.keySet()) { TreeGrid treeGrid = treeGrids.get(name); treeGrid.deselectAllRecords(); this.currentSectionViewId = null; this.currentPageViewId = null; } } private void selectSectionPageTreeGridNode(String sectionName, String pageName) { for (String name : treeGrids.keySet()) { TreeGrid treeGrid = treeGrids.get(name); if (!name.equals(sectionName)) { treeGrid.deselectAllRecords(); } else { Tree tree = treeGrid.getTree(); TreeNode node = tree.find(sectionName + "/" + pageName); if (node != null) { treeGrid.selectSingleRecord(node); } else { CoreGUI.getErrorHandler().handleError(MSG.view_leftNav_unknownPage(pageName, sectionName)); } } } } public Set<Permission> getGlobalPermissions() { return globalPermissions; } private EnhancedVLayout decorateWithTitleBar(ViewName viewName, Canvas pageBody){ EnhancedVLayout vLayout = new EnhancedVLayout(); vLayout.setWidth100(); vLayout.setHeight100(); // default to 24x24 otherwise use 16x16 String iconPath = (viewName.getIcon().getIcon24x24Path() != null) ? viewName.getIcon().getIcon24x24Path() : viewName.getIcon().getIcon16x16Path(); vLayout.addMember(new TitleBar(viewName.getTitle(), iconPath)); vLayout.addMember(pageBody); return vLayout; } }