/*
* RHQ Management Platform
* Copyright (C) 2005-2010 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.dashboard;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.authz.Permission;
import org.rhq.core.domain.common.EntityContext;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.dashboard.Dashboard;
import org.rhq.core.domain.dashboard.DashboardPortlet;
import org.rhq.core.domain.resource.ResourceTypeFacet;
import org.rhq.core.domain.resource.composite.ResourceComposite;
import org.rhq.core.domain.resource.group.GroupCategory;
import org.rhq.core.domain.resource.group.composite.ResourceGroupComposite;
import org.rhq.coregui.client.CoreGUI;
import org.rhq.coregui.client.ImageManager;
import org.rhq.coregui.client.UserSessionManager;
import org.rhq.coregui.client.components.form.ColorButtonItem;
import org.rhq.coregui.client.dashboard.portlets.groups.GroupAlertsPortlet;
import org.rhq.coregui.client.dashboard.portlets.groups.GroupBundleDeploymentsPortlet;
import org.rhq.coregui.client.dashboard.portlets.groups.GroupConfigurationUpdatesPortlet;
import org.rhq.coregui.client.dashboard.portlets.groups.GroupEventsPortlet;
import org.rhq.coregui.client.dashboard.portlets.groups.GroupMetricsPortlet;
import org.rhq.coregui.client.dashboard.portlets.groups.GroupOobsPortlet;
import org.rhq.coregui.client.dashboard.portlets.groups.GroupOperationsPortlet;
import org.rhq.coregui.client.dashboard.portlets.groups.GroupPkgHistoryPortlet;
import org.rhq.coregui.client.dashboard.portlets.resource.ResourceAlertsPortlet;
import org.rhq.coregui.client.dashboard.portlets.resource.ResourceBundleDeploymentsPortlet;
import org.rhq.coregui.client.dashboard.portlets.resource.ResourceConfigurationUpdatesPortlet;
import org.rhq.coregui.client.dashboard.portlets.resource.ResourceEventsPortlet;
import org.rhq.coregui.client.dashboard.portlets.resource.ResourceMetricsPortlet;
import org.rhq.coregui.client.dashboard.portlets.resource.ResourceOobsPortlet;
import org.rhq.coregui.client.dashboard.portlets.resource.ResourceOperationsPortlet;
import org.rhq.coregui.client.dashboard.portlets.resource.ResourcePkgHistoryPortlet;
import org.rhq.coregui.client.gwt.GWTServiceLookup;
import org.rhq.coregui.client.util.Log;
import org.rhq.coregui.client.util.enhanced.EnhancedVLayout;
import org.rhq.coregui.client.util.message.Message;
import org.rhq.coregui.client.util.preferences.UserPreferenceNames.UiSubsystem;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.widgets.AnimationCallback;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.events.ColorSelectedEvent;
import com.smartgwt.client.widgets.form.events.ColorSelectedHandler;
import com.smartgwt.client.widgets.form.fields.ButtonItem;
import com.smartgwt.client.widgets.form.fields.CanvasItem;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.StaticTextItem;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
import com.smartgwt.client.widgets.layout.LayoutSpacer;
import com.smartgwt.client.widgets.menu.IMenuButton;
import com.smartgwt.client.widgets.menu.Menu;
import com.smartgwt.client.widgets.menu.MenuItem;
import com.smartgwt.client.widgets.menu.events.ClickHandler;
import com.smartgwt.client.widgets.menu.events.ItemClickEvent;
import com.smartgwt.client.widgets.menu.events.ItemClickHandler;
import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent;
/**
* @author Jay Shaughnessy
* @author Greg Hinkle
* @author Simeon Pinder
*/
public class DashboardView extends EnhancedVLayout {
private DashboardContainer dashboardContainer;
private Dashboard storedDashboard;
private boolean editMode = false;
PortalLayout portalLayout;
DynamicForm editForm;
IMenuButton addPortlet;
HashSet<PortletWindow> portletWindows = new HashSet<PortletWindow>();
private static String STOP = MSG.view_dashboards_portlets_refresh_none();
private static String REFRESH1 = MSG.view_dashboards_portlets_refresh_one_min();
private static String REFRESH5 = MSG.view_dashboards_portlets_refresh_multiple_min(String.valueOf(5));
private static String REFRESH10 = MSG.view_dashboards_portlets_refresh_multiple_min(String.valueOf(10));
private static Integer STOP_VALUE = 0;
private static Integer REFRESH1_VALUE = 1 * 60000;
private static Integer REFRESH5_VALUE = 5 * 60000;
private static Integer REFRESH10_VALUE = 10 * 60000;
private HashMap<Integer, String> refreshMenuMappings;
private MenuItem[] refreshMenuItems;
private int refreshInterval = 0;
private IMenuButton refreshMenuButton;
private EntityContext context;
private ResourceGroupComposite groupComposite = null;
private ResourceComposite resourceComposite = null;
// this is used to prevent an odd smartgwt problem where onInit() can get called multiple times if
// the view is set to a Tab's pane.
private boolean isInitialized = false;
private PortletWindow maximizedPortlet = null;
/**
* Convenience constructor for subsystem context.
*
* @param dashboardContainer
* @param storedDashboard
*/
public DashboardView(DashboardContainer dashboardContainer, Dashboard storedDashboard) {
this(dashboardContainer, storedDashboard, EntityContext.forSubsystemView(), null);
}
/**
* @param dashboardContainer
* @param storedDashboard
* @param context
* @param composite ResourceComposite, ResourceGroupComposite or null depending on context
*/
public DashboardView(DashboardContainer dashboardContainer, Dashboard storedDashboard, EntityContext context,
Object composite) {
super();
this.dashboardContainer = dashboardContainer;
this.storedDashboard = storedDashboard;
// This is a workaround for the fact that RHQ 4.1 and earlier wrongly allowed the user to save a dashboard with
// 0 columns.
if (this.storedDashboard.getColumns() == 0) {
this.storedDashboard.setColumns(1);
}
this.context = context;
switch (this.context.getType()) {
case Resource: {
if (null == composite) {
throw new IllegalArgumentException("null composite for resource context");
}
this.resourceComposite = (ResourceComposite) composite;
break;
}
case ResourceGroup: {
if (null == composite) {
throw new IllegalArgumentException("null composite for group context");
}
this.groupComposite = (ResourceGroupComposite) composite;
break;
}
}
}
@Override
protected void onInit() {
if (!isInitialized) {
super.onInit();
this.setWidth100();
this.setHeight100();
this.addMember(buildEditForm());
buildPortlets();
isInitialized = true;
}
}
public void rebuild() {
// destroy all of the portlets and recreate from scratch
portalLayout.removeFromParent();
portalLayout.destroy();
portalLayout = null;
portletWindows.clear();
buildPortlets();
}
@Override
protected void onDraw() {
super.onDraw();
setEditMode(editMode);
}
public void buildPortlets() {
this.setBackgroundColor(storedDashboard.getConfiguration().getSimpleValue(Dashboard.CFG_BACKGROUND,
"transparent"));
try {
portalLayout = new PortalLayout(this, storedDashboard.getColumns(), storedDashboard.getColumnWidths());
} catch (IllegalArgumentException iae) {
String[] columnWidths = storedDashboard.getColumnWidths();
int numColumns = storedDashboard.getColumns();
if ((null != columnWidths && columnWidths.length > numColumns)) {
String[] columnWidthsFixed = new String[numColumns];
System.arraycopy(columnWidths, 0, columnWidthsFixed, 0, numColumns - 1);
columnWidthsFixed[numColumns-1] = "*";
Configuration cleanConfiguration = new Configuration();
cleanConfiguration.setProperties(storedDashboard.getConfiguration().getProperties());
storedDashboard.setConfiguration(cleanConfiguration);
storedDashboard.setColumnWidths(columnWidthsFixed);
portalLayout = new PortalLayout(this, storedDashboard.getColumns(), storedDashboard.getColumnWidths());
Log.error("Invalid column widths (more widths than columns) "
+ Arrays.toString(columnWidths));
save();
} else {
throw iae;
}
}
portalLayout.setOverflow(Overflow.AUTO);
portalLayout.setWidth100();
portalLayout.setHeight100();
loadPortletWindows();
addMember(portalLayout);
}
protected boolean canEditName() {
return true;
}
private DynamicForm buildEditForm() {
editForm = new DynamicForm();
editForm.setMargin(5);
editForm.setAutoWidth();
editForm.setNumCols(canEditName() ? 12 : 10);
TextItem nameItem = null;
if (dashboardContainer.supportsDashboardNameEdit()) {
nameItem = new TextItem("name", MSG.common_title_dashboard_name());
nameItem.setValue(storedDashboard.getName());
nameItem.setLength(200);
nameItem.setWrapTitle(false);
nameItem.addBlurHandler(new BlurHandler() {
public void onBlur(BlurEvent blurEvent) {
FormItem nameItem = blurEvent.getItem();
String name = (String) nameItem.getValue();
String trimmedName = (name == null) ? "" : name.trim();
if (dashboardContainer.isValidDashboardName(trimmedName)) {
storedDashboard.setName(trimmedName);
save();
dashboardContainer.updateDashboardNames();
} else {
// TODO: i18n
Message message = new Message("There is already a dashboard named '" + trimmedName
+ "'. Please specify a name that is not already in use.", Message.Severity.Error, EnumSet
.of(Message.Option.Transient));
CoreGUI.getMessageCenter().notify(message);
nameItem.setValue(storedDashboard.getName());
}
}
});
}
final StaticTextItem numColItem = new StaticTextItem();
numColItem.setTitle(MSG.common_title_columns());
numColItem.setValue(storedDashboard.getColumns());
numColItem.setWrapTitle(false);
ButtonItem addColumn = new ButtonItem("addColumn", MSG.common_title_add_column());
addColumn.setAutoFit(true);
addColumn.setStartRow(false);
addColumn.setEndRow(false);
final ButtonItem removeColumn = new ButtonItem("removeColumn", MSG.common_title_remove_column());
removeColumn.setAutoFit(true);
removeColumn.setStartRow(false);
removeColumn.setEndRow(false);
removeColumn.setDisabled(storedDashboard.getColumns() == 1);
addColumn.addClickHandler(new com.smartgwt.client.widgets.form.fields.events.ClickHandler() {
public void onClick(com.smartgwt.client.widgets.form.fields.events.ClickEvent event) {
portalLayout.addMember(new PortalColumn());
numColItem.setValue(storedDashboard.getColumns() + 1);
storedDashboard.setColumns(storedDashboard.getColumns() + 1);
removeColumn.setDisabled(storedDashboard.getColumns() == 1);
save();
}
});
removeColumn.addClickHandler(new com.smartgwt.client.widgets.form.fields.events.ClickHandler() {
public void onClick(com.smartgwt.client.widgets.form.fields.events.ClickEvent event) {
Canvas[] columns = portalLayout.getMembers();
int numColumns = columns.length;
if (numColumns > 0) {
PortalColumn lastColumn = (PortalColumn) columns[numColumns - 1];
for (Canvas portletWindow : lastColumn.getMembers()) {
storedDashboard.removePortlet(((PortletWindow) portletWindow).getStoredPortlet());
}
portalLayout.removeMember(lastColumn);
numColItem.setValue(numColumns - 1);
storedDashboard.setColumns(storedDashboard.getColumns() - 1);
removeColumn.setDisabled(storedDashboard.getColumns() == 1);
save();
}
}
});
// build the menu of valid portlets for this context, sorted by portlet name
final Menu addPortletMenu = new Menu();
LinkedHashMap<String, String> valueMap;
switch (context.getType()) {
case SubsystemView:
valueMap = PortletFactory.getGlobalPortletMenuMap();
break;
case ResourceGroup:
valueMap = processPortletNameMapForGroup(this.groupComposite);
// In addition to the group-specific portlets, make the global portlets available
valueMap.putAll(PortletFactory.getGlobalPortletMenuMap());
break;
case Resource:
valueMap = processPortletNameMapForResource(this.resourceComposite);
// In addition to the resource-specific portlets, make the global portlets available
valueMap.putAll(PortletFactory.getGlobalPortletMenuMap());
break;
default:
throw new IllegalStateException("Unsupported context [" + context + "]");
}
Map<UiSubsystem, Boolean> showSubsystems = UserSessionManager.getUserPreferences().getShowUiSubsystems();
for (Iterator<String> i = valueMap.keySet().iterator(); i.hasNext();) {
String portletKey = i.next();
if (PortletFactory.canBeAdded(portletKey, showSubsystems)) {
String portletName = valueMap.get(portletKey);
MenuItem menuItem = new MenuItem(portletName);
menuItem.setAttribute("portletKey", portletKey);
addPortletMenu.addItem(menuItem);
}
}
addPortlet = new IMenuButton(MSG.common_title_add_portlet(), addPortletMenu);
addPortlet.setIcon("[skin]/images/actions/add.png");
addPortlet.setAutoFit(true);
addPortletMenu.addItemClickHandler(new ItemClickHandler() {
public void onItemClick(ItemClickEvent itemClickEvent) {
String key = itemClickEvent.getItem().getAttribute("portletKey");
String name = itemClickEvent.getItem().getTitle();
try {
addPortlet(key, name);
} catch (Exception ex) {
CoreGUI.getErrorHandler().handleError(MSG.view_dashboardsManager_error3(), ex);
}
}
});
CanvasItem addCanvas = new CanvasItem();
addCanvas.setShowTitle(false);
addCanvas.setCanvas(addPortlet);
addCanvas.setStartRow(false);
addCanvas.setEndRow(false);
ColorButtonItem picker = new ColorButtonItem("colorButton", MSG.common_title_background());
picker.setStartRow(false);
picker.setEndRow(false);
picker.setCurrentColor(storedDashboard.getConfiguration().getSimpleValue(Dashboard.CFG_BACKGROUND,
"transparent"));
picker.setColorSelectedHandler(new ColorSelectedHandler() {
@Override
public void onColorSelected(ColorSelectedEvent event) {
String selectedColor = event.getColor();
if (selectedColor != null) {
setBackgroundColor(selectedColor);
storedDashboard.getConfiguration().put(new PropertySimple(Dashboard.CFG_BACKGROUND, selectedColor));
save();
}
}
});
//refresh interval
Menu refreshMenu = new Menu();
refreshMenu.setShowShadow(true);
refreshMenu.setShadowDepth(10);
refreshMenu.setAutoWidth();
refreshMenu.setHeight(15);
ClickHandler menuClick = new ClickHandler() {
@Override
public void onClick(MenuItemClickEvent event) {
String selection = event.getItem().getTitle();
refreshInterval = 0;
if (selection != null) {
if (selection.equals(STOP)) {
refreshInterval = STOP_VALUE;
} else if (selection.equals(REFRESH1)) {
refreshInterval = REFRESH1_VALUE;
} else if (selection.equals(REFRESH5)) {
refreshInterval = REFRESH5_VALUE;
} else if (selection.equals(REFRESH10)) {
refreshInterval = REFRESH10_VALUE;
} else {//unable to locate value disable refresh
refreshInterval = STOP_VALUE;//
}
UserSessionManager.getUserPreferences().setPageRefreshInterval(refreshInterval,
new UpdatePortletRefreshCallback());
}
}
};
String[] refreshIntervals = { STOP, REFRESH1, REFRESH5, REFRESH10 };
Integer[] refreshValues = { STOP_VALUE, REFRESH1_VALUE, REFRESH5_VALUE, REFRESH10_VALUE };
refreshMenuMappings = new HashMap<Integer, String>();
refreshMenuItems = new MenuItem[refreshIntervals.length];
int retrievedRefreshInterval = REFRESH1_VALUE;
if (null != UserSessionManager.getUserPreferences()) {
retrievedRefreshInterval = UserSessionManager.getUserPreferences().getPageRefreshInterval();
}
for (int i = 0; i < refreshIntervals.length; i++) {
MenuItem item = new MenuItem(refreshIntervals[i], "");
item.addClickHandler(menuClick);
refreshMenuMappings.put(refreshValues[i], refreshIntervals[i]);
if (retrievedRefreshInterval == refreshValues[i]) {
item.setIcon(ImageManager.getAvailabilityIcon(true));
}
refreshMenuItems[i] = item;
}
refreshMenu.setItems(refreshMenuItems);
refreshMenuButton = new IMenuButton(MSG.common_title_refreshInterval(), refreshMenu);
refreshMenu.setAutoHeight();
refreshMenuButton.getMenu().setItems(refreshMenuItems);
refreshMenuButton.setWidth(140);
refreshMenuButton.setShowTitle(true);
refreshMenuButton.setTop(0);
refreshMenuButton.setIconOrientation("left");
CanvasItem refreshCanvas = new CanvasItem();
refreshCanvas.setShowTitle(false);
refreshCanvas.setCanvas(refreshMenuButton);
refreshCanvas.setStartRow(false);
refreshCanvas.setEndRow(false);
if (null != nameItem) {
editForm.setItems(nameItem, addCanvas, numColItem, addColumn, removeColumn, picker, refreshCanvas);
} else {
editForm.setItems(addCanvas, numColItem, addColumn, removeColumn, picker, refreshCanvas);
}
updateRefreshMenu();
this.refreshMenuButton.markForRedraw();
markForRedraw();
//attempt to initialize
editForm.markForRedraw();
markForRedraw();
return editForm;
}
/** Return the relevant sorted value map for the resource
*/
public static LinkedHashMap<String, String> processPortletNameMapForResource(ResourceComposite composite) {
LinkedHashMap<String, String> resourceMenuMap = PortletFactory.getResourcePortletMenuMap();
if ((composite != null) && (composite.getResource() != null)) {
resourceMenuMap = new LinkedHashMap<String, String>(resourceMenuMap);
// filter out portlets not relevent for facets
Set<ResourceTypeFacet> facets = composite.getResourceFacets().getFacets();
if (!facets.isEmpty()) {
// Operation related portlets
if (!facets.contains(ResourceTypeFacet.OPERATION)) {
resourceMenuMap.remove(ResourceOperationsPortlet.KEY);
}
// MEASUREMENT related portlets(METRICS)
if (!facets.contains(ResourceTypeFacet.MEASUREMENT)) {
resourceMenuMap.remove(ResourceMetricsPortlet.KEY);
resourceMenuMap.remove(ResourceOobsPortlet.KEY);
}
// Content related portlets
if (!facets.contains(ResourceTypeFacet.CONTENT)) {
resourceMenuMap.remove(ResourcePkgHistoryPortlet.KEY);
}
// Event related portlets
if (!facets.contains(ResourceTypeFacet.EVENT)) {
resourceMenuMap.remove(ResourceEventsPortlet.KEY);
}
// Configuration related portlets
if (!facets.contains(ResourceTypeFacet.CONFIGURATION)) {
resourceMenuMap.remove(ResourceConfigurationUpdatesPortlet.KEY);
}
// Bundle related portlets
if (!facets.contains(ResourceTypeFacet.BUNDLE)) {
resourceMenuMap.remove(ResourceBundleDeploymentsPortlet.KEY);
}
}
}
return resourceMenuMap;
}
/** Return the relevant sorted value map for the group
*/
public static LinkedHashMap<String, String> processPortletNameMapForGroup(ResourceGroupComposite composite) {
LinkedHashMap<String, String> groupMenuMap = PortletFactory.getGroupPortletMenuMap();
if ((composite != null) && (composite.getResourceGroup() != null)) {
groupMenuMap = new LinkedHashMap<String, String>(groupMenuMap);
// filter out portlets not relevent for facets
Set<ResourceTypeFacet> facets = composite.getResourceFacets().getFacets();
GroupCategory groupCategory = composite.getResourceGroup().getGroupCategory();
// if not a compatible group do some pruning.
if (groupCategory != GroupCategory.COMPATIBLE) {
groupMenuMap.remove(GroupOperationsPortlet.KEY);
groupMenuMap.remove(GroupMetricsPortlet.KEY);
groupMenuMap.remove(GroupOobsPortlet.KEY);
groupMenuMap.remove(GroupPkgHistoryPortlet.KEY);
groupMenuMap.remove(GroupConfigurationUpdatesPortlet.KEY);
groupMenuMap.remove(GroupBundleDeploymentsPortlet.KEY);
} else {
// for compatible may still need to do some pruning.
if (!facets.isEmpty()) {
// Operations related portlets(Config,PkgHistory)
if (!facets.contains(ResourceTypeFacet.OPERATION)) {
groupMenuMap.remove(GroupOperationsPortlet.KEY);
}
// MEASUREMENT related portlets(METRICS)
if (!facets.contains(ResourceTypeFacet.MEASUREMENT)) {
groupMenuMap.remove(GroupMetricsPortlet.KEY);
groupMenuMap.remove(GroupOobsPortlet.KEY);
}
// CONTENT related portlets(CONTENT)
if (!facets.contains(ResourceTypeFacet.CONTENT)) {
groupMenuMap.remove(GroupPkgHistoryPortlet.KEY);
}
// CONFIGURATION related portlets(CONFIGURATION)
if (!facets.contains(ResourceTypeFacet.CONFIGURATION)) {
groupMenuMap.remove(GroupConfigurationUpdatesPortlet.KEY);
}
// BUNDLE related portlets(BUNDLE)
if (!facets.contains(ResourceTypeFacet.BUNDLE)) {
groupMenuMap.remove(GroupBundleDeploymentsPortlet.KEY);
}
}
}
}
return groupMenuMap;
}
private void loadPortletWindows() {
Map<UiSubsystem, Boolean> showSubsystems = UserSessionManager.getUserPreferences().getShowUiSubsystems();
for (int i = 0; i < storedDashboard.getColumns(); i++) {
for (DashboardPortlet storedPortlet : storedDashboard.getPortlets(i)) {
try {
if (PortletFactory.canBeAdded(storedPortlet.getPortletKey(), showSubsystems)) {
PortletWindow portletWindow = new PortletWindow(this, storedPortlet, context);
portletWindow.setTitle(storedPortlet.getName());
portletWindow.setHeight(storedPortlet.getHeight());
portletWindow.setVisible(true);
portletWindows.add(portletWindow);
portalLayout.addPortletWindow(portletWindow, i);
}
} catch (Exception ex) {
CoreGUI.getErrorHandler().handleError(MSG.view_dashboardsManager_error2(), ex);
continue;
}
}
}
}
protected void addPortlet(String portletKey, String portletName) {
DashboardPortlet storedPortlet = new DashboardPortlet(portletName, portletKey, 250);
storedDashboard.addPortlet(storedPortlet);
final PortletWindow newPortletWindow = new PortletWindow(this, storedPortlet, context);
newPortletWindow.setTitle(portletName);
newPortletWindow.setHeight(350);
newPortletWindow.setVisible(false);
portletWindows.add(newPortletWindow);
portalLayout.addPortletWindow(newPortletWindow, storedPortlet.getColumn());
PortalColumn portalColumn = portalLayout.getPortalColumn(storedPortlet.getColumn());
// also insert a blank spacer element, which will trigger the built-in
// animateMembers layout animation
final LayoutSpacer placeHolder = new LayoutSpacer();
// placeHolder.setRect(newPortlet.getRect());
portalColumn.addMember(placeHolder); // add to top
// create an outline around the clicked button
final Canvas outline = new Canvas();
outline.setLeft(editForm.getAbsoluteLeft() + addPortlet.getLeft());
outline.setTop(editForm.getAbsoluteTop());
outline.setWidth(addPortlet.getWidth());
outline.setHeight(addPortlet.getHeight());
outline.setBorder("2px solid 8289A6");
outline.draw();
outline.bringToFront();
outline.animateRect(newPortletWindow.getPageLeft(), newPortletWindow.getPageTop(),
newPortletWindow.getVisibleWidth(), newPortletWindow.getViewportHeight(), new AnimationCallback() {
public void execute(boolean earlyFinish) {
// callback at end of animation - destroy placeholder and outline; show the new portlet
placeHolder.destroy();
outline.destroy();
newPortletWindow.show();
}
}, 750);
save();
}
public void removePortlet(PortletWindow portletWindow) {
storedDashboard.removePortlet(portletWindow.getStoredPortlet());
this.portletWindows.remove(portletWindow);
save();
}
public void save(Dashboard dashboard) {
if (null != dashboard) {
storedDashboard = dashboard;
save();
}
}
public void save() {
save((AsyncCallback<Dashboard>) null);
}
public String[] updatePortalColumnWidths() {
int numColumns = storedDashboard.getColumns();
int totalPixelWidth = 0;
int[] columnPixelWidths = new int[numColumns];
for (int i = 0; i < numColumns; ++i) {
PortalColumn col = portalLayout.getPortalColumn(i);
totalPixelWidth += col.getWidth();
columnPixelWidths[i] = col.getWidth();
}
String[] columnWidths = new String[numColumns];
columnWidths[numColumns - 1] = "*";
for (int i = 0; i < numColumns - 1; ++i) {
columnWidths[i] = String.valueOf((columnPixelWidths[i] * 100 / totalPixelWidth)) + "%";
}
storedDashboard.setColumnWidths(columnWidths);
return columnWidths;
}
public void save(final AsyncCallback<Dashboard> callback) {
// a variety of edits (dragResize, add/remove column, etc) can cause column width changes. Update them
// prior to every save.
updatePortalColumnWidths();
// since we reset storedDashboard after the async update completes, block modification of the dashboard
// during that interval.
DashboardView.this.disable();
GWTServiceLookup.getDashboardService().storeDashboard(storedDashboard, new AsyncCallback<Dashboard>() {
public void onFailure(Throwable caught) {
CoreGUI.getErrorHandler().handleError(MSG.view_dashboardManager_error(), caught);
DashboardView.this.enable();
if (null != callback) {
callback.onFailure(caught);
}
}
public void onSuccess(Dashboard result) {
CoreGUI.getMessageCenter().notify(
new Message(MSG.view_dashboardManager_saved(result.getName()), Message.Severity.Info));
// The portlet definitions have been merged and updated, reset the portlet windows with the
// up to date portlets.
updatePortletWindows(result);
storedDashboard = result;
if (null != callback) {
callback.onSuccess(result);
}
DashboardView.this.enable();
}
});
}
private void updatePortletWindows(Dashboard result) {
if (result != null) {
for (PortletWindow portletWindow : portletWindows) {
for (DashboardPortlet updatedPortlet : result.getPortlets()) {
if (equalsDashboardPortlet(portletWindow.getStoredPortlet(), updatedPortlet)) {
portletWindow.setStoredPortlet(updatedPortlet);
// restarting portlet auto-refresh with newest settings
Portlet view = portletWindow.getView();
if (view instanceof AutoRefreshPortlet) {
((AutoRefreshPortlet) view).startRefreshCycle();
}
break;
}
}
}
}
}
/**
* This is an enhanced equals for portlets that allows equality for unpersisted portlets. At times (like addPortlet)
* a portlet may have been associated with its window prior to being persisted. In this case we can consider
* it equal if it is associated with the same dashboard(1) and has the same positioning. Note that key-name pairing
* can not be used for equality as a dashboard is allowed to have the same portlet multiple times, with a default
* name. But they can not hold the same position.
* <pre>
* (1) Even the dashboard comparison has been made flexible. To allow for lazy persist of the dashboard (to
* allow for the default group or resource dashboard to not be persisted) we allow the dash comparison
* to be done by name if an entity id is 0. This should be safe as dashboard names are set prior to
* persist, and should be unique for the session user.
*
* @param storedPortlet
* @param updatedPortlet
* @return
*/
private boolean equalsDashboardPortlet(DashboardPortlet storedPortlet, DashboardPortlet updatedPortlet) {
if (storedPortlet.equals(updatedPortlet)) {
return true;
}
// make sure at least one portlet is not persisted for pseudo-equality
if (storedPortlet.getId() > 0 && updatedPortlet.getId() > 0) {
return false;
}
// must match position for pseudo-equality
if (storedPortlet.getColumn() != updatedPortlet.getColumn()) {
return false;
}
if (storedPortlet.getIndex() != updatedPortlet.getIndex()) {
return false;
}
// must match dash (ids if persisted, otherwise name) for pseudo-equality
boolean unpersistedDash = (storedPortlet.getDashboard().getId() == 0 || updatedPortlet.getDashboard().getId() == 0);
boolean dashMatchId = (!unpersistedDash && (storedPortlet.getDashboard().getId() == updatedPortlet
.getDashboard().getId()));
boolean dashMatchName = (unpersistedDash && storedPortlet.getDashboard().getName()
.equals(updatedPortlet.getDashboard().getName()));
if (!(dashMatchId || dashMatchName)) {
return false;
}
return true;
}
public void delete() {
if (null != this.storedDashboard && this.storedDashboard.getId() > 0) {
GWTServiceLookup.getDashboardService().removeDashboard(this.storedDashboard.getId(),
new AsyncCallback<Void>() {
public void onFailure(Throwable caught) {
CoreGUI.getErrorHandler().handleError(MSG.view_dashboardManager_deleteFail(), caught);
}
public void onSuccess(Void result) {
CoreGUI.getMessageCenter().notify(
new Message(MSG.view_dashboardManager_deleted(storedDashboard.getName()),
Message.Severity.Info));
}
});
}
}
public void resize() {
portalLayout.resize();
}
public Dashboard getDashboard() {
return storedDashboard;
}
public Set<Permission> getGlobalPermissions() {
return dashboardContainer.getGlobalPermissions();
}
public void setEditMode(boolean editMode) {
this.editMode = editMode;
// don't allow resizing in min/max in edit mode
for (PortletWindow portletWindow : portletWindows) {
portletWindow.hideSizingHeaderControls(editMode);
}
if (editMode) {
this.editForm.show();
//
} else {
this.editForm.hide();
}
this.editForm.markForRedraw();
this.portalLayout.show();
redraw();
this.portalLayout.markForRedraw();
}
public class UpdatePortletRefreshCallback implements AsyncCallback<Subject> {
public void onSuccess(Subject subject) {
String m;
if (refreshInterval > 0) {
m = MSG.view_dashboards_portlets_refresh_success1();
} else {
m = MSG.view_dashboards_portlets_refresh_success2();
}
CoreGUI.getMessageCenter().notify(new Message(m, Message.Severity.Info));
updateRefreshMenu();
save();
}
public void onFailure(Throwable throwable) {
String m;
if (refreshInterval > 0) {
m = MSG.view_dashboards_portlets_refresh_fail1();
} else {
m = MSG.view_dashboards_portlets_refresh_fail2();
}
CoreGUI.getMessageCenter().notify(new Message(m, Message.Severity.Error));
// Revert back to our original favorite status, since the server update failed.
updateRefreshMenu();
}
}
public void updateRefreshMenu() {
if (refreshMenuItems != null) {
int retrievedRefreshInterval = REFRESH1_VALUE;
if (null != UserSessionManager.getUserPreferences()) {
retrievedRefreshInterval = UserSessionManager.getUserPreferences().getPageRefreshInterval();
}
String currentSelection = refreshMenuMappings.get(retrievedRefreshInterval);
if (currentSelection != null) {
//iterate over menu items and update icon details
for (int i = 0; i < refreshMenuItems.length; i++) {
MenuItem menu = refreshMenuItems[i];
if (currentSelection.equals(menu.getTitle())) {
menu.setIcon(ImageManager.getAvailabilityIcon(true));
} else {
menu.setIcon("");
}
refreshMenuItems[i] = menu;
}
//update the menu
refreshMenuButton.getMenu().setItems(refreshMenuItems);
}
}
if (this.refreshMenuButton != null) {
this.refreshMenuButton.markForRedraw();
}
}
public Dashboard getStoredDashboard() {
return storedDashboard;
}
public EntityContext getContext() {
return context;
}
public ResourceGroupComposite getGroupComposite() {
return groupComposite;
}
public ResourceComposite getResourceComposite() {
return resourceComposite;
}
public boolean isMaximized() {
return (maximizedPortlet != null);
}
public PortletWindow getMaximizePortlet() {
return maximizedPortlet;
}
public void maximizePortlet(PortletWindow portletWindow) {
if (isMaximized()) {
return;
}
maximizedPortlet = portletWindow;
int numColumns = storedDashboard.getColumns();
for (int i = 0; i < numColumns; ++i) {
PortalColumn col = portalLayout.getPortalColumn(i);
Canvas portlet = col.getMember(portletWindow.getID());
if (null == portlet) {
col.hide();
} else {
for (Canvas member : col.getMembers()) {
if (!member.equals(portlet)) {
member.hide();
} else {
((PortletWindow) member).hideSizingHeaderControls(true);
member.setHeight100();
}
}
}
}
portalLayout.markForRedraw();
}
public void restorePortlet() {
if (!isMaximized()) {
return;
}
int numColumns = storedDashboard.getColumns();
for (int i = 0; i < numColumns; ++i) {
PortalColumn col = portalLayout.getPortalColumn(i);
if (!col.isVisible()) {
col.show();
} else {
for (Canvas member : col.getMembers()) {
if (!member.isVisible()) {
member.show();
} else {
((PortletWindow) member).hideSizingHeaderControls(false);
member.setHeight(maximizedPortlet.getStoredPortlet().getHeight());
}
}
}
}
maximizedPortlet = null;
portalLayout.markForRedraw();
}
// If we redraw the dashboard then also redraw the portlets so that everything is up to date
@Override
public void redraw() {
super.redraw();
for (PortletWindow pw : portletWindows) {
// I think this should work with markForRedraw but for some reason it does not
try {
((Canvas) pw.getView()).redraw();
} catch (Exception ex) {
CoreGUI.getErrorHandler().handleError(MSG.view_dashboardsManager_error4(), ex);
}
}
}
}