/*
* 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, version 2, as
* published by the Free Software Foundation, and/or the GNU Lesser
* General Public License, version 2.1, also as published by the Free
* Software Foundation.
*
* 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 and the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* and the GNU Lesser General Public License along with this program;
* if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.rhq.coregui.client.dashboard;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.types.TabBarControls;
import com.smartgwt.client.util.BooleanCallback;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.tab.Tab;
import com.smartgwt.client.widgets.tab.events.CloseClickHandler;
import com.smartgwt.client.widgets.tab.events.TabCloseClickEvent;
import com.smartgwt.client.widgets.tab.events.TabSelectedEvent;
import com.smartgwt.client.widgets.tab.events.TabSelectedHandler;
import org.rhq.core.domain.authz.Permission;
import org.rhq.core.domain.common.ProductInfo;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.criteria.DashboardCriteria;
import org.rhq.core.domain.dashboard.Dashboard;
import org.rhq.core.domain.dashboard.DashboardCategory;
import org.rhq.core.domain.dashboard.DashboardPortlet;
import org.rhq.core.domain.util.PageList;
import org.rhq.core.domain.util.PageOrdering;
import org.rhq.coregui.client.BookmarkableView;
import org.rhq.coregui.client.CoreGUI;
import org.rhq.coregui.client.InitializableView;
import org.rhq.coregui.client.LinkManager;
import org.rhq.coregui.client.PermissionsLoadedListener;
import org.rhq.coregui.client.PermissionsLoader;
import org.rhq.coregui.client.UserSessionManager;
import org.rhq.coregui.client.ViewPath;
import org.rhq.coregui.client.components.tab.NamedTab;
import org.rhq.coregui.client.components.tab.NamedTabSet;
import org.rhq.coregui.client.components.view.ViewName;
import org.rhq.coregui.client.dashboard.portlets.recent.alerts.RecentAlertsPortlet;
import org.rhq.coregui.client.dashboard.portlets.recent.operations.OperationHistoryPortlet;
import org.rhq.coregui.client.dashboard.portlets.recent.problems.ProblemResourcesPortlet;
import org.rhq.coregui.client.dashboard.portlets.summary.InventorySummaryPortlet;
import org.rhq.coregui.client.dashboard.portlets.util.MashupPortlet;
import org.rhq.coregui.client.dashboard.portlets.util.MessagePortlet;
import org.rhq.coregui.client.gwt.DashboardGWTServiceAsync;
import org.rhq.coregui.client.gwt.GWTServiceLookup;
import org.rhq.coregui.client.util.Log;
import org.rhq.coregui.client.util.enhanced.EnhancedIButton;
import org.rhq.coregui.client.util.enhanced.EnhancedVLayout;
import org.rhq.coregui.client.util.preferences.UserPreferenceNames.UiSubsystem;
/**
* @author Jay Shaughnessy
* @author Greg Hinkle
*/
public class DashboardsView extends EnhancedVLayout implements DashboardContainer, BookmarkableView, InitializableView {
public static final ViewName VIEW_ID = new ViewName("Dashboards", MSG.view_dashboards_title());
// Each NamedTab is a Dashboard, name=Dashboard.id, title=Dashboard.name
private NamedTabSet tabSet;
// The ID
private String selectedTabName;
private IButton editButton;
private boolean editMode = false;
private Map<String, Dashboard> dashboardsByName;
private DashboardView selectedDashboardView;
private Dashboard selectedDashboard;
private DashboardGWTServiceAsync dashboardService = GWTServiceLookup.getDashboardService();
// Capture the user's global permissions for use by any dashboard or portlet that may need it for rendering.
private HashSet<Permission> globalPermissions;
private boolean initialized = false;
public DashboardsView() {
super();
setOverflow(Overflow.AUTO);
setPadding(5);
setWidth100();
setHeight100();
}
@Override
protected void onInit() {
super.onInit();
DashboardCriteria criteria = new DashboardCriteria();
criteria.addSortName(PageOrdering.ASC);
dashboardService.findDashboardsByCriteria(criteria, new AsyncCallback<PageList<Dashboard>>() {
public void onFailure(Throwable caught) {
CoreGUI.getErrorHandler().handleError(MSG.view_dashboardsManager_error1(), caught);
}
public void onSuccess(final PageList<Dashboard> result) {
// now, a second async call to load global perms
new PermissionsLoader().loadExplicitGlobalPermissions(new PermissionsLoadedListener() {
public void onPermissionsLoaded(Set<Permission> permissions) {
globalPermissions = new HashSet<Permission>(permissions);
if (result.isEmpty()) {
// if the user has no dashboards persist a default dashboard for him to work with. In
// this way we're always working with a persisted dashboard and real entities.
addDefaultDashboard();
} else {
updateDashboards(result);
}
initialized = true;
}
});
}
});
}
private void addDefaultDashboard() {
dashboardService.storeDashboard(getDefaultDashboard(), new AsyncCallback<Dashboard>() {
public void onFailure(Throwable caught) {
CoreGUI.getErrorHandler().handleError(MSG.view_dashboardsManager_error1(), caught);
}
public void onSuccess(Dashboard defaultDashboard) {
List<Dashboard> dashboards = new ArrayList<Dashboard>(1);
dashboards.add(defaultDashboard);
updateDashboards(dashboards);
}
});
}
private void updateDashboards(List<Dashboard> dashboards) {
Canvas[] members = getMembers();
removeMembers(members);
if (null != tabSet) {
tabSet.destroy();
}
this.dashboardsByName = new HashMap<String, Dashboard>(dashboards.size());
for (Dashboard dashboard : dashboards) {
this.dashboardsByName.put(dashboard.getName(), dashboard);
}
tabSet = new NamedTabSet();
tabSet.setWidth100();
tabSet.setHeight100();
tabSet.setStyleName("dashboardTabs");
editButton = new EnhancedIButton(editMode ? MSG.common_title_view_mode() : MSG.common_title_edit_mode());
editButton.setAutoFit(true);
editButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent clickEvent) {
editMode = !editMode;
editButton.setTitle(editMode ? MSG.common_title_view_mode() : MSG.common_title_edit_mode());
if (selectedDashboardView.isMaximized()) {
selectedDashboardView.restorePortlet();
}
selectedDashboardView.setEditMode(editMode);
}
});
final IButton newDashboardButton = new EnhancedIButton(MSG.common_title_new_dashboard());
newDashboardButton.setAutoFit(true);
newDashboardButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent clickEvent) {
newDashboardButton.disable();
addNewDashboard(newDashboardButton);
}
});
HLayout buttons = new HLayout(5);
buttons.addMember(editButton);
buttons.addMember(newDashboardButton);
tabSet.setTabBarControls(TabBarControls.TAB_SCROLLER, TabBarControls.TAB_PICKER, buttons);
tabSet.addTabSelectedHandler(new TabSelectedHandler() {
public void onTabSelected(TabSelectedEvent tabSelectedEvent) {
NamedTab selectedTab = tabSet.getTabByTitle(tabSelectedEvent.getTab().getTitle());
/*
* do not record history item if initially loading the DashboardsView. if the selectedDashboardView is
* null, suppression will prevent redirection from #Dashboards to #Dashboards/dashboardId,
* which would require the user to hit the back button twice to return to the previous page.
*/
if (selectedDashboardView != null) {
Log.debug(" ***** selectedTab: " + selectedTab.getName() + ", " + selectedTab.getTitle());
CoreGUI.goToView(LinkManager.getDashboardLink(Integer.valueOf(selectedTab.getName())), true);
}
selectedDashboardView = (DashboardView) selectedTab.getPane();
selectedDashboard = selectedDashboardView.getDashboard();
editButton.setTitle(editMode ? MSG.common_title_view_mode() : MSG.common_title_edit_mode());
selectedDashboardView.setEditMode(editMode);
// If re-selecting a Dashboard, make sure it, and its portlets, are up to date
if (selectedDashboardView.isDrawn()) {
// I think this should work with markForRedraw but for some reason it does not
selectedDashboardView.redraw();
}
}
});
for (Dashboard dashboard : dashboards) {
String dashboardName = String.valueOf(dashboard.getId());
String dashboardTitle = dashboard.getName();
DashboardView dashboardView = new DashboardView(this, dashboard);
Tab tab = new NamedTab(new ViewName(dashboardName, dashboardTitle), null);
tab.setPane(dashboardView);
tab.setCanClose(true);
tabSet.addTab(tab);
if (dashboard.getName().equals(selectedTabName)) {
tabSet.selectTab(tab);
}
}
tabSet.addCloseClickHandler(new CloseClickHandler() {
public void onCloseClick(final TabCloseClickEvent tabCloseClickEvent) {
tabCloseClickEvent.cancel();
final DashboardView dashboardView = (DashboardView) tabCloseClickEvent.getTab().getPane();
SC.ask(MSG.view_dashboards_confirm1() + " [" + dashboardView.getStoredDashboard().getName() + "]?",
new BooleanCallback() {
public void execute(Boolean confirmed) {
if (confirmed) {
dashboardsByName.remove(tabCloseClickEvent.getTab().getTitle());
tabSet.removeTab(tabCloseClickEvent.getTab());
dashboardView.delete();
// if it's the last tab go back to a default tab
if (0 == tabSet.getTabs().length) {
addDefaultDashboard();
}
}
}
});
}
});
addMember(tabSet);
}
protected Dashboard getDefaultDashboard() {
Dashboard dashboard = new Dashboard();
dashboard.setName(MSG.common_title_default());
dashboard.setCategory(DashboardCategory.INVENTORY);
dashboard.setColumns(2);
// only leftmost column width is currently settable, the rest are equally divided
dashboard.setColumnWidths("32%");
Map<UiSubsystem, Boolean> showSubsystems = UserSessionManager.getUserPreferences().getShowUiSubsystems();
ProductInfo productInfo = CoreGUI.get().getProductInfo();
boolean isRHQ = (productInfo != null) && "RHQ".equals(productInfo.getShortName());
// Left Column
int columnIndex = 0;
int rowIndex = 0;
if (isRHQ) {
DashboardPortlet welcome = new DashboardPortlet(MessagePortlet.NAME, MessagePortlet.KEY, 250);
dashboard.addPortlet(welcome, columnIndex, rowIndex++);
}
DashboardPortlet summary = new DashboardPortlet(InventorySummaryPortlet.NAME, InventorySummaryPortlet.KEY, 250);
dashboard.addPortlet(summary, columnIndex, rowIndex++);
DashboardPortlet news = new DashboardPortlet(MashupPortlet.NAME, MashupPortlet.KEY, 300);
news.getConfiguration().put(new PropertySimple("address", "mashup.html"));
dashboard.addPortlet(news, columnIndex, rowIndex++);
// Right Column
columnIndex = 1;
rowIndex = 0;
if (showSubsystems.get(UiSubsystem.ALERTS)) {
DashboardPortlet recentAlerts = new DashboardPortlet(RecentAlertsPortlet.NAME, RecentAlertsPortlet.KEY, 250);
dashboard.addPortlet(recentAlerts, columnIndex, rowIndex++);
}
DashboardPortlet problemResources = new DashboardPortlet(ProblemResourcesPortlet.NAME,
ProblemResourcesPortlet.KEY, 250);
//initialize config for the problemResources portlet.
problemResources.getConfiguration().put(
new PropertySimple(ProblemResourcesPortlet.PROBLEM_RESOURCE_SHOW_MAX,
ProblemResourcesPortlet.defaultShowMax));
problemResources.getConfiguration().put(
new PropertySimple(ProblemResourcesPortlet.PROBLEM_RESOURCE_SHOW_HRS,
ProblemResourcesPortlet.defaultShowHours));
dashboard.addPortlet(problemResources, columnIndex, rowIndex++);
if (showSubsystems.get(UiSubsystem.OPERATIONS)) {
DashboardPortlet operations = new DashboardPortlet(OperationHistoryPortlet.NAME,
OperationHistoryPortlet.KEY, 200);
dashboard.addPortlet(operations, columnIndex, rowIndex++);
}
return dashboard;
}
public boolean isValidDashboardName(String name) {
if (name == null || name.equals("")) {
return false;
}
return (!this.dashboardsByName.containsKey(name));
}
public void addNewDashboard(final IButton newDashboardButton) {
int i = 0;
String availableDashboardName = null;
while (availableDashboardName == null) {
String candidateDashboardName = MSG.common_title_custom() + i++;
if (!this.dashboardsByName.containsKey(candidateDashboardName)) {
availableDashboardName = candidateDashboardName;
}
}
Dashboard dashboard = new Dashboard();
dashboard.setCategory(DashboardCategory.INVENTORY);
dashboard.setName(availableDashboardName);
dashboard.setColumns(2);
// only leftmost column width is currently settable, the rest are equally divided
dashboard.setColumnWidths("32%");
dashboardService.storeDashboard(dashboard, new AsyncCallback<Dashboard>() {
public void onFailure(Throwable caught) {
CoreGUI.getErrorHandler().handleError(MSG.view_dashboardsManager_error1(), caught);
newDashboardButton.enable();
}
public void onSuccess(Dashboard result) {
String dashboardName = String.valueOf(result.getId());
String dashboardTitle = result.getName();
dashboardsByName.put(dashboardTitle, result); // update map so name can not be reused
DashboardView dashboardView = new DashboardView(DashboardsView.this, result);
NamedTab tab = new NamedTab(new ViewName(dashboardName, dashboardTitle), null);
tab.setPane(dashboardView);
tab.setCanClose(true);
editMode = true;
tabSet.addTab(tab);
tabSet.selectTab(tab);
newDashboardButton.enable();
}
});
}
public void renderView(ViewPath viewPath) {
// make sure we have at least a default dashboard tab
if (null == tabSet || 0 == tabSet.getTabs().length) {
return;
}
NamedTab[] tabs = tabSet.getTabs();
// if nothing selected or pathtab does not exist, default to the first tab
NamedTab selectedTab = tabs[0];
selectedTabName = selectedTab.getName();
if (!viewPath.isEnd()) {
String pathTabName = viewPath.getCurrent().getPath();
for (NamedTab tab : tabSet.getTabs()) {
if (tab.getName().equals(pathTabName)) {
selectedTab = tab;
selectedTabName = pathTabName;
break;
}
}
}
if (!selectedTab.equals(tabSet.getSelectedTab())) {
tabSet.selectTab(selectedTab);
} else if (viewPath.isRefresh()) {
refresh();
}
}
public Dashboard getDashboard() {
return selectedDashboard;
}
@Override
public boolean isInitialized() {
return initialized;
}
public HashSet<Permission> getGlobalPermissions() {
return globalPermissions;
}
public boolean supportsDashboardNameEdit() {
return true;
}
public void updateDashboardNames() {
for (Tab t : tabSet.getTabs()) {
DashboardView view = (DashboardView) t.getPane();
t.setTitle(view.getDashboard().getName());
}
}
@Override
public void refresh() {
if (isInitialized()) {
if (null != selectedDashboardView && selectedDashboardView.isDrawn()) {
selectedDashboardView.rebuild();
}
}
}
}