package org.rhq.coregui.client.dashboard.portlets.recent.problems; /* * RHQ Management Platform * Copyright (C) 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. */ //import java.text.SimpleDateFormat; import static org.rhq.coregui.client.resource.ProblemResourcesDataSource.Field.ALERTS; import static org.rhq.coregui.client.resource.ProblemResourcesDataSource.Field.AVAILABILITY; import static org.rhq.coregui.client.resource.ProblemResourcesDataSource.Field.RESOURCE; import java.util.Date; import java.util.List; import com.google.gwt.user.client.Timer; import com.smartgwt.client.types.Overflow; import com.smartgwt.client.widgets.Canvas; import com.smartgwt.client.widgets.HTMLFlow; import com.smartgwt.client.widgets.Label; import com.smartgwt.client.widgets.form.DynamicForm; import com.smartgwt.client.widgets.form.events.SubmitValuesEvent; import com.smartgwt.client.widgets.form.events.SubmitValuesHandler; import com.smartgwt.client.widgets.form.fields.SelectItem; import com.smartgwt.client.widgets.grid.CellFormatter; import com.smartgwt.client.widgets.grid.HoverCustomizer; import com.smartgwt.client.widgets.grid.ListGrid; import com.smartgwt.client.widgets.grid.ListGridField; import com.smartgwt.client.widgets.grid.ListGridRecord; import org.rhq.core.domain.common.EntityContext; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.core.domain.configuration.definition.ConfigurationDefinition; import org.rhq.core.domain.configuration.definition.PropertyDefinitionSimple; import org.rhq.core.domain.configuration.definition.PropertySimpleType; import org.rhq.core.domain.dashboard.DashboardPortlet; import org.rhq.coregui.client.LinkManager; import org.rhq.coregui.client.components.table.IconField; import org.rhq.coregui.client.components.table.Table; import org.rhq.coregui.client.components.table.TableWidget; import org.rhq.coregui.client.dashboard.AutoRefreshPortlet; import org.rhq.coregui.client.dashboard.AutoRefreshUtil; import org.rhq.coregui.client.dashboard.CustomSettingsPortlet; import org.rhq.coregui.client.dashboard.Portlet; import org.rhq.coregui.client.dashboard.PortletViewFactory; import org.rhq.coregui.client.dashboard.PortletWindow; import org.rhq.coregui.client.inventory.resource.AncestryUtil; import org.rhq.coregui.client.resource.ProblemResourcesDataSource; import org.rhq.coregui.client.util.MeasurementUtility; import org.rhq.coregui.client.util.enhanced.EnhancedHLayout; /** * A view that displays a paginated table of Resources with alerts, * and/or Resources reported unavailable. * * @author Simeon Pinder */ public class ProblemResourcesPortlet extends Table<ProblemResourcesDataSource> implements CustomSettingsPortlet, AutoRefreshPortlet { // A non-displayed, persisted identifier for the portlet public static final String KEY = "ProblemResources"; // A default displayed, persisted name for the portlet public static final String NAME = MSG.view_portlet_defaultName_problemResources(); //keys for smart gwt elements. should be unique public static final String PROBLEM_RESOURCE_SHOW_HRS = "max-problems-query-span"; public static final String PROBLEM_RESOURCE_SHOW_MAX = "max-problems-shown"; // set on initial configuration, the window for this portlet view. private PortletWindow portletWindow; //reference to datasource private ProblemResourcesDataSource dataSource; //constants public static final int unlimited = -1; public static final String unlimitedString = MSG.common_label_unlimited(); public static final String defaultShowMax = "20"; public static final String defaultShowHours = "24"; private Timer refreshTimer; public ProblemResourcesPortlet() { super(NAME, true); setShowHeader(false); setShowFooter(true); //disable footer refresh setShowFooterRefresh(false); setOverflow(Overflow.VISIBLE); //insert the datasource this.dataSource = new ProblemResourcesDataSource(this); setDataSource(this.dataSource); } /** Gets access to the ListGrid from super class for editing. * */ @Override protected void configureTable() { ListGrid listGrid = getListGrid(); if (listGrid != null) { addExtraWidget(new TimeRange(this), false); } ListGridField resourceField = new ListGridField(RESOURCE.propertyName(), RESOURCE.title()); resourceField.setCellFormatter(new CellFormatter() { public String format(Object o, ListGridRecord listGridRecord, int i, int i1) { String url = LinkManager.getResourceLink(listGridRecord.getAttributeAsInt("id")); return LinkManager.getHref(url, o.toString()); } }); resourceField.setShowHover(true); resourceField.setHoverCustomizer(new HoverCustomizer() { public String hoverHTML(Object value, ListGridRecord listGridRecord, int rowNum, int colNum) { return AncestryUtil.getResourceHoverHTML(listGridRecord, 0); } }); ListGridField ancestryField = AncestryUtil.setupAncestryListGridField(); ListGridField alertsField = new ListGridField(ALERTS.propertyName(), ALERTS.title(), 70); IconField availabilityField = new IconField(AVAILABILITY.propertyName(), AVAILABILITY.title(), 70); setListGridFields(resourceField, ancestryField, alertsField, availabilityField); } @Override public ProblemResourcesDataSource getDataSource() { return (ProblemResourcesDataSource) super.getDataSource(); } /** Implement configure action. * */ @Override public void configure(PortletWindow portletWindow, DashboardPortlet storedPortlet) { if (null == this.portletWindow && null != portletWindow) { this.portletWindow = portletWindow; } if ((null == storedPortlet) || (null == storedPortlet.getConfiguration())) { return; } int configuredValue; //determine configuration value for ProblemResourceShowMax configuredValue = populateConfigurationValue(storedPortlet, PROBLEM_RESOURCE_SHOW_MAX, defaultShowMax); getDataSource().setMaximumProblemResourcesToDisplay(configuredValue); //determine configuration value for ProblemResourceShowHrs configuredValue = populateConfigurationValue(storedPortlet, PROBLEM_RESOURCE_SHOW_HRS, defaultShowHours); getDataSource().setMaximumProblemResourcesWithinHours(configuredValue); } /**Determine which configuration value to use given the property passed in. * * @param storedPortlet DashboardPortlet instance * @param propertyKey Widget key * @param defaultKeyValue default value to be used if property not yet set. * @return value of configuration, Ex. 1,5,10,unlimited. */ private int populateConfigurationValue(DashboardPortlet storedPortlet, String propertyKey, String defaultKeyValue) { int configuredValue = Integer.valueOf(defaultKeyValue); if ((storedPortlet == null) || (storedPortlet.getConfiguration() == null)) { return configuredValue; } if (storedPortlet.getConfiguration().getSimple(propertyKey) != null) { String retrieved = storedPortlet.getConfiguration().getSimple(propertyKey).getStringValue(); // protect against legacy issue with non-numeric values try { configuredValue = Integer.parseInt(retrieved); } catch (NumberFormatException e) { configuredValue = unlimited; } } else { storedPortlet.getConfiguration().put(new PropertySimple(propertyKey, defaultKeyValue)); } return configuredValue; } @Override public Canvas getHelpCanvas() { return new HTMLFlow(MSG.view_portlet_help_problemResources()); } /** Build custom for to dispaly the Portlet Configuration settings. * */ public DynamicForm getCustomSettingsForm() { final DynamicForm form = new DynamicForm(); final DashboardPortlet storedPortlet = portletWindow.getStoredPortlet(); //-------------combobox for number of resource to display on the dashboard final SelectItem maximumProblemResourcesComboBox = new SelectItem(PROBLEM_RESOURCE_SHOW_MAX); maximumProblemResourcesComboBox.setTitle(MSG.common_title_display()); maximumProblemResourcesComboBox.setHint("<nobr><b> " + MSG.view_portlet_problemResources_maxDisplaySetting() + "</b></nobr>"); //spinder 9/3/10: the following is required workaround to disable editability of combobox. maximumProblemResourcesComboBox.setType("selection"); //define acceptable values for display amount String[] acceptableDisplayValues = { "5", "10", "15", "20", "30", unlimitedString }; maximumProblemResourcesComboBox.setValueMap(acceptableDisplayValues); //set width of dropdown display region maximumProblemResourcesComboBox.setWidth(100); int configuredValue = populateConfigurationValue(storedPortlet, PROBLEM_RESOURCE_SHOW_MAX, defaultShowMax); String selectedValue = configuredValue == unlimited ? unlimitedString : String.valueOf(configuredValue); //prepopulate the combobox with the previously stored selection maximumProblemResourcesComboBox.setDefaultValue(selectedValue); //------------- Build second combobox for timeframe for problem resources search. final SelectItem maximumTimeProblemResourcesComboBox = new SelectItem(PROBLEM_RESOURCE_SHOW_HRS); maximumTimeProblemResourcesComboBox.setTitle(MSG.common_title_over() + " "); maximumTimeProblemResourcesComboBox.setHint("<nobr><b> " + MSG.common_unit_hours() + " </b></nobr>"); //spinder 9/3/10: the following is required workaround to disable editability of combobox. maximumTimeProblemResourcesComboBox.setType("selection"); String[] acceptableTimeValues = { "1", "4", "8", "24", "48", unlimitedString }; maximumTimeProblemResourcesComboBox.setValueMap(acceptableTimeValues); maximumTimeProblemResourcesComboBox.setWidth(100); configuredValue = populateConfigurationValue(storedPortlet, PROBLEM_RESOURCE_SHOW_HRS, defaultShowHours); selectedValue = configuredValue == unlimited ? unlimitedString : String.valueOf(configuredValue); //prepopulate the combobox with the previously stored selection maximumTimeProblemResourcesComboBox.setDefaultValue(selectedValue); //insert fields form.setFields(maximumProblemResourcesComboBox, maximumTimeProblemResourcesComboBox); //submit handler form.addSubmitValuesHandler(new SubmitValuesHandler() { @Override public void onSubmitValues(SubmitValuesEvent event) { String value = (String) form.getValue(PROBLEM_RESOURCE_SHOW_MAX); if (value != null) { // convert display string to stored integer if necessary value = unlimitedString.equals(value) ? String.valueOf(unlimited) : value; storedPortlet.getConfiguration().put(new PropertySimple(PROBLEM_RESOURCE_SHOW_MAX, value)); } value = (String) form.getValue(PROBLEM_RESOURCE_SHOW_HRS); if (value != null) { // convert display string to stored integer if necessary value = unlimitedString.equals(value) ? String.valueOf(unlimited) : value; storedPortlet.getConfiguration().put(new PropertySimple(PROBLEM_RESOURCE_SHOW_HRS, value)); } configure(portletWindow, storedPortlet); refresh(); } }); return form; } public static final class Factory implements PortletViewFactory { public static final PortletViewFactory INSTANCE = new Factory(); public final Portlet getInstance(EntityContext context) { return new ProblemResourcesPortlet(); } } public ConfigurationDefinition getConfigurationDefinition() { ConfigurationDefinition definition = new ConfigurationDefinition(MSG.view_portlet_configure_definitionTitle(), MSG.view_portlet_configure_definitionDesc()); definition.put(new PropertyDefinitionSimple(PROBLEM_RESOURCE_SHOW_MAX, MSG .view_portlet_problemResources_config_display_maximum(), true, PropertySimpleType.INTEGER)); definition.put(new PropertyDefinitionSimple(PROBLEM_RESOURCE_SHOW_HRS, MSG .view_portlet_problemResources_config_display_range(), true, PropertySimpleType.INTEGER)); return definition; } public void refreshTableInfo() { if (isShowFooter()) { long begin = 0; List<Long> bounds = MeasurementUtility.calculateTimeFrame(getDataSource() .getMaximumProblemResourcesWithinHours(), MeasurementUtility.UNIT_HOURS); begin = bounds.get(0); long end = bounds.get(1); //if range spans greater than year then change formatter. if ((end - begin) > MeasurementUtility.ONE_YEAR) { timeRange = new String[] { MeasurementUtility.getDateTimeYearFormatter().format(new Date(begin)), MeasurementUtility.getDateTimeYearFormatter().format(new Date(end)) }; } else { timeRange = new String[] { MeasurementUtility.getDateTimeFormatter().format(new Date(begin)), MeasurementUtility.getDateTimeFormatter().format(new Date(end)) }; } //remove selected count as portlet is view only. Selection not used. getTableInfo().setContents(MSG.common_title_total() + ": " + getListGrid().getTotalRows()); } } private String[] timeRange = null; public String[] getTimeRange() { return timeRange; } public void startRefreshCycle() { refreshTimer = AutoRefreshUtil.startRefreshCycleWithPageRefreshInterval(this, this, refreshTimer); } @Override protected void onDestroy() { AutoRefreshUtil.onDestroy(refreshTimer); super.onDestroy(); } public boolean isRefreshing() { return false; } @Override public void refresh() { if (!isRefreshing()) { super.refresh(); } } } /**Construct table widget Label to display timerange settings used with latest datasource query. * * @author spinder */ class TimeRange extends EnhancedHLayout implements TableWidget { private Label label = new Label(); private ProblemResourcesPortlet portlet = null; public TimeRange(ProblemResourcesPortlet problemResourcesPortlet) { super(); this.portlet = problemResourcesPortlet; } @Override public void refresh(ListGrid listGrid) { this.label.setWidth(400); this.label.setContents(MSG.view_portlet_problemResources_config_display_range2(portlet.getTimeRange()[0], portlet.getTimeRange()[1])); } @Override protected void onDraw() { super.onDraw(); addMember(this.label); } }