/*
* 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.components.measurement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.DateDisplayFormat;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.ButtonItem;
import com.smartgwt.client.widgets.form.fields.CheckboxItem;
import com.smartgwt.client.widgets.form.fields.DateTimeItem;
import com.smartgwt.client.widgets.form.fields.SelectItem;
import com.smartgwt.client.widgets.form.fields.SpacerItem;
import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
import com.smartgwt.client.widgets.form.fields.events.ClickEvent;
import com.smartgwt.client.widgets.form.fields.events.ClickHandler;
import com.smartgwt.client.widgets.form.validator.CustomValidator;
import com.smartgwt.client.widgets.grid.ListGrid;
import org.rhq.coregui.client.CoreGUI;
import org.rhq.coregui.client.Messages;
import org.rhq.coregui.client.components.table.TableWidget;
import org.rhq.coregui.client.util.MeasurementUtility;
import org.rhq.coregui.client.util.message.Message;
import org.rhq.coregui.client.util.message.Message.Severity;
/**
* @author Simeon Pinder
* @author Greg Hinkle
*/
public abstract class AbstractMeasurementRangeEditor extends DynamicForm implements TableWidget {
protected static final Messages MSG = CoreGUI.getMessages();
//keyed map of translated date units Ex. minutes,hours,days
protected static LinkedHashMap<String, String> lastUnits;
//array of values available for displaying/selecting 'last N hours|minutes|days'.
protected static final String[] lastValues;
protected boolean advanced;
private ButtonItem advancedSimpleButton;
protected SelectItem simpleLastValuesItem;
protected SelectItem simpleLastUnitsItem;
protected DateTimeItem advancedStartItem;
protected DateTimeItem advancedEndItem;
private boolean displaySetButton = true;
private boolean displayEnableButton = false;
private boolean displayRangeItemGrouping = false;
private boolean displayCheckboxLabel = false;
protected CheckboxItem enableRangeItem;
private SpacerItem space;
private ButtonItem setButton;
public static final String ENABLE_RANGE_ITEM = "ENABLE_RANGE_ITEM";
public static final String ADVANCED_BUTTON_ITEM = "advanced";
public static final String SIMPLE_VALUE_ITEM = "lastValues";
public static final String SIMPLE_UNIT_ITEM = "lastUnits";
public static final String ADVANCED_START_ITEM = "start";
public static final String ADVANCED_END_ITEM = "end";
public static final String SET_ITEM = "set";
static {
Messages MSG = CoreGUI.getMessages();
lastUnits = new LinkedHashMap<String, String>(3);
lastUnits.put(String.valueOf(MeasurementUtility.UNIT_MINUTES), MSG.common_unit_minutes());
lastUnits.put(String.valueOf(MeasurementUtility.UNIT_HOURS), MSG.common_unit_hours());
lastUnits.put(String.valueOf(MeasurementUtility.UNIT_DAYS), MSG.common_unit_days());
lastValues = new String[] { "4", "8", "12", "24", "30", "36", "48", "60", "90", "120" };
}
public AbstractMeasurementRangeEditor() {
super();
setNumCols(10);
setWrapItemTitles(false);
setAlign(Alignment.LEFT);
}
/**
* Returns the current range that is persisted. Note this may NOT be the begin and end times
* as shown in the UI if the user changed the values but did not hit the set button.
* @return begin/end epoch times in a list
*/
public abstract List<Long> getBeginEndTimes();
public abstract MetricRangePreferences getMetricRangePreferences();
public abstract void setMetricRangeProperties(MetricRangePreferences prefs);
@Override
protected void onInit() {
super.onInit();
if (isDisplayRangeItemGrouping()) {
setIsGroup(true);
setGroupTitle("Filter by: Time");
}
enableRangeItem = new CheckboxItem(ENABLE_RANGE_ITEM, "Filter By Time:");
enableRangeItem.setShowTitle(isDisplayCheckboxLabel());
enableRangeItem.setShowLabel(isDisplayCheckboxLabel());
enableRangeItem.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
boolean enableRange = Boolean.valueOf(event.getItem().getValue() + "");
enableMeasurementRange(enableRange);
}
});
//combobox of last items
simpleLastValuesItem = new SelectItem(SIMPLE_VALUE_ITEM, MSG.view_measureRange_last());
simpleLastValuesItem.setValueMap(lastValues);
simpleLastValuesItem.setTitleAlign(Alignment.LEFT);
//combobox of units of time
simpleLastUnitsItem = new SelectItem(SIMPLE_UNIT_ITEM);
simpleLastUnitsItem.setValueMap(lastUnits);
simpleLastUnitsItem.setShowTitle(false);
//time range start from
advancedStartItem = new DateTimeItem(ADVANCED_START_ITEM, MSG.view_measureRange_start());
advancedStartItem.setTitleAlign(Alignment.LEFT);
advancedStartItem.setUseMask(true);
advancedStartItem.setDisplayFormat(DateDisplayFormat.TOUSSHORTDATE);
//time range end
advancedEndItem = new DateTimeItem(ADVANCED_END_ITEM, MSG.common_title_end());
advancedEndItem.setUseMask(true);
advancedEndItem.setDisplayFormat(DateDisplayFormat.TOUSSHORTDATE);
//time validator, start should be before end
CustomValidator timeValidator = new CustomValidator() {
protected boolean condition(Object value) {
return advancedEndItem.getValueAsDate().after(advancedStartItem.getValueAsDate());
}
};
timeValidator.setErrorMessage(MSG.view_measureTable_startBeforeEnd());
advancedStartItem.setValidators(timeValidator);
setButton = new ButtonItem(SET_ITEM, MSG.common_button_set());
setButton.setStartRow(false);
setButton.setEndRow(false);
setButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
MetricRangePreferences prefs = new MetricRangePreferences();
prefs.explicitBeginEnd = advanced;
if (advanced) {
try {
if (validate()) {
prefs.begin = advancedStartItem.getValueAsDate().getTime();
prefs.end = advancedEndItem.getValueAsDate().getTime();
if (null != prefs.begin && null != prefs.end && prefs.begin > prefs.end) {
CoreGUI.getMessageCenter().notify(new Message(MSG.view_measureTable_startBeforeEnd()));
} else {
setMetricRangeProperties(prefs);
}
}
} catch (Exception ex) {
// some of the digits are not filled correctly
Map<String, String> errors = new HashMap<String, String>();
errors.put(ADVANCED_END_ITEM, "MM/DD/YYYY HH:MM");
errors.put(ADVANCED_START_ITEM, "MM/DD/YYYY HH:MM");
setErrors(errors, true);
}
} else {
prefs.lastN = Integer.valueOf(simpleLastValuesItem.getValueAsString());
prefs.unit = Integer.valueOf(simpleLastUnitsItem.getValueAsString());
setMetricRangeProperties(prefs);
}
}
});
advancedSimpleButton = new ButtonItem(ADVANCED_BUTTON_ITEM, MSG.common_button_advanced());
advancedSimpleButton.setStartRow(false);
advancedSimpleButton.setEndRow(false);
advancedSimpleButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent clickEvent) {
advanced = !advanced;
update();
}
});
space = new SpacerItem();
space.setWidth(300);
MetricRangePreferences metricRangePrefs = getMetricRangePreferences();
if (metricRangePrefs != null) {
advanced = (metricRangePrefs.explicitBeginEnd);
}
if (displaySetButton) {
setItems(simpleLastValuesItem, simpleLastUnitsItem, advancedStartItem, advancedEndItem, setButton,
advancedSimpleButton, space);
} else {//not displaying Set button
if (displayEnableButton) {
setItems(enableRangeItem, simpleLastValuesItem, simpleLastUnitsItem, advancedStartItem,
advancedEndItem, advancedSimpleButton, space);
} else {
setItems(simpleLastValuesItem, simpleLastUnitsItem, advancedStartItem, advancedEndItem,
advancedSimpleButton, space);
}
}
update();
}
private void assignDefaultsToAdvancedItems() {
advancedStartItem.setValue(new Date(System.currentTimeMillis() - (1000L * 60 * 60 * 8)));
advancedEndItem.setValue(new Date());
}
private void assignDefaultsToSimpleItems() {
simpleLastValuesItem.setValue("8");
simpleLastUnitsItem.setValue(String.valueOf(MeasurementUtility.UNIT_HOURS));
}
protected void enableMeasurementRange(boolean enableRange) {
if (enableRange) {
simpleLastValuesItem.disable();
simpleLastUnitsItem.disable();
advancedStartItem.disable();
advancedEndItem.disable();
advancedSimpleButton.disable();
} else {
simpleLastValuesItem.enable();
simpleLastUnitsItem.enable();
advancedStartItem.enable();
advancedEndItem.enable();
advancedSimpleButton.enable();
markForRedraw();
}
}
protected void update() {
if (advanced) {
advancedSimpleButton.setTitle(MSG.view_measureRange_simple());
showItem(ADVANCED_START_ITEM);
showItem(ADVANCED_END_ITEM);
hideItem(SIMPLE_VALUE_ITEM);
hideItem(SIMPLE_UNIT_ITEM);
} else {
advancedSimpleButton.setTitle(MSG.common_button_advanced());
hideItem(ADVANCED_START_ITEM);
hideItem(ADVANCED_END_ITEM);
showItem(SIMPLE_VALUE_ITEM);
showItem(SIMPLE_UNIT_ITEM);
}
// populate the fields - first with defaults in case we have no prefs, then with the appropriate prefs
assignDefaultsToSimpleItems();
assignDefaultsToAdvancedItems();
try {
MetricRangePreferences metricRangePrefs = getMetricRangePreferences();
if (metricRangePrefs.explicitBeginEnd) {
if (metricRangePrefs.begin != null && metricRangePrefs.end != null) {
advancedStartItem.setValue(new Date(metricRangePrefs.begin.longValue()));
advancedEndItem.setValue(new Date(metricRangePrefs.end.longValue()));
}
} else {
if (lastUnits.containsKey(String.valueOf(metricRangePrefs.unit))) {
simpleLastUnitsItem.setValue(String.valueOf(metricRangePrefs.unit));
}
if (Arrays.asList(lastValues).contains(String.valueOf(metricRangePrefs.lastN))) {
simpleLastValuesItem.setValue(String.valueOf(metricRangePrefs.lastN));
}
}
} catch (Exception e) {
// in case any odd errors occur (like bad format of preference strings), just fill in some defaults
CoreGUI.getMessageCenter().notify(
new Message("Failed to get range user preferences, using defaults", e, Severity.Warning));
assignDefaultsToSimpleItems();
assignDefaultsToAdvancedItems();
}
markForRedraw();
}
@Override
public void refresh(ListGrid listGrid) {
update();
}
public static class MetricRangePreferences {
// if readOnly is true, then the beginning and ending range dates are specified with explicit dates
// if readOnly is false, then the time is relative to NOW and is specified as <lastN> units of <unit> time
public boolean explicitBeginEnd;
// simple, when readOnly is false
public int lastN;
public int unit; // see MeasurementUtility.UNIT_xxx
// advanced, when readOnly is true
public Long begin;
public Long end;
/**
* Returns a two element <code>List</code> of <code>Long</code> objects representing the begin and end times (in
* milliseconds since the epoch) of the time frame.
**/
public ArrayList<Long> getBeginEndTimes() {
if (explicitBeginEnd) {
ArrayList<Long> times = new ArrayList<Long>(2);
times.add(begin);
times.add(end);
return times;
} else {
return MeasurementUtility.calculateTimeFrame(lastN, unit);
}
}
public String toString() {
return (explicitBeginEnd) ? "[begin=" + begin + end + ",end=" + end + "]" : "[lastN=" + lastN + ",unit="
+ unit + "]";
}
}
/**
* Returns the SetButton so you can set a click handler from a dialog box
* @return ButtonItem setButton
*/
public ButtonItem getSetButton() {
return setButton;
}
public boolean isDisplaySetButton() {
return displaySetButton;
}
public void setDisplaySetButton(boolean displaySetButton) {
this.displaySetButton = displaySetButton;
}
public boolean isDisplayEnableButton() {
return displayEnableButton;
}
public void setDisplayEnableButton(boolean displayEnableButton) {
this.displayEnableButton = displayEnableButton;
}
public boolean isAdvanced() {
return advanced;
}
public void setAdvanced(boolean advanced) {
this.advanced = advanced;
}
public boolean isDisplayRangeItemGrouping() {
return displayRangeItemGrouping;
}
public void setDisplayRangeItemGrouping(boolean displayRangeItemGrouping) {
this.displayRangeItemGrouping = displayRangeItemGrouping;
}
public boolean isDisplayCheckboxLabel() {
return displayCheckboxLabel;
}
public void setDisplayCheckboxLabel(boolean displayCheckboxLabel) {
this.displayCheckboxLabel = displayCheckboxLabel;
}
}