/*
 This file is part of the software framework JStatCom, 
 a library for building applications for data based analysis.

 Copyright (C) 2000-2005  Markus Kraetzig

 This library is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as
 published by the Free Software Foundation; either version 2.1 of the
 License, or (at your option) any later version.

 This library 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
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 USA
 */

package com.jstatcom.ts;

import org.apache.log4j.Logger;

import com.jstatcom.component.IValTextField;
import com.jstatcom.component.MatrixBorder;

/**
 * Component for display and selection of a TSDateRange. It
 * interpretes an input string and validates it against a parser and a defined
 * range. The range that is displayed in this text field always includes its
 * bounds. This component can be costumized by setting an overall range that
 * must enclose the range that is selected. This is ensured by the validation
 * mechanism.
 * 

* This class fires a "TSDateRange" property change, if a new date was set. * * @see com.jstatcom.ts.TSDateRange * @see com.jstatcom.parser.TSDateParser * @author Markus Kraetzig */ public final class TSDateRangeSelector extends IValTextField { private static final Logger log = Logger .getLogger(TSDateRangeSelector.class); /** * Enclosing range that the input must be in with. */ private TSDateRange enclosingRange = null; /** * Currently displayed range. */ private TSDateRange tSDateRange = null; /** * Minimum observations to be available within the range. */ private int minNumberOfObs = 1; /** * Create a TSDateRangeSelectorwith the range set to * [1960 q1,1982 q4]. */ public TSDateRangeSelector() { super(); TSDate t1 = TSDate.valueOf("1960 q1"); TSDate t2 = TSDate.valueOf("1982 q4"); enclosingRange = new TSDateRange(t1, t2); setTSDateRange(enclosingRange); setBorder(MatrixBorder.getInstanceSmall()); setSize(44, getHeight()); } /** * Gets the overall range that the selected range must be in with. * * @return the enclosing range */ public TSDateRange getEnclosingRange() { return enclosingRange; } /** * Gets the minimum number of observations selectable by this component. * * @return minimum number of observations */ public int getMinNumberOfObs() { return minNumberOfObs; } /** * Gets the currently displayed date range. * * @return the currently selected range */ public TSDateRange getTSDateRange() { return tSDateRange; } /** * Returns the currently displayed date range as an array of two indices * relative to the lower bound of the overall range. The index starts from * 0. * * @return int array with int[0] = index of lower bound, int[1] = index of * upper bound */ public int[] getTSDateRangeAsIndices() { return enclosingRange.indicesForRange(tSDateRange); } /** * Error handling routine if validation failed. Displays an error message * and sets back the range value to the last valid one. * * @param msg * an error message */ public void handleError(String msg) { super.handleError(msg + "\nThe previous value " + tSDateRange + " is restored."); setTSDateRange(tSDateRange); } /** * Sets the display to the maximum possible range, which is the enclosing * range. */ public void maxRange() { setTSDateRange(enclosingRange); } /** * Sets the range that the selected range must be in with by setting an * initial date and the desired number of available periods within the * range. * * @param newStart * new start of bounding range * @param numberOfPeriods > * 0 to define the end of the bounding range */ public void setEnclosingRange(TSDate newStart, int numberOfPeriods) { setEnclosingRange(new TSDateRange(newStart, newStart .addPeriods(numberOfPeriods - 1))); } /** * Sets the overall range that the selected range must be in with. The * selected range is not changed unless it violates the new range setting. * * @param newOverallRange * the new bounding range * @throws IllegalArgumentException * if (newOverallRange == null) */ public void setEnclosingRange(TSDateRange newOverallRange) { if (newOverallRange == null) throw new IllegalArgumentException("Range cannot be null."); enclosingRange = newOverallRange; if (enclosingRange.encloses(tSDateRange) != null) { // Try to get overlapping range. TSDateRange newRange = enclosingRange.commonRange(tSDateRange); if (newRange != null) // Set overlapping range. setTSDateRange(newRange); else // No overlapping range, set overall range. setTSDateRange(enclosingRange); } } /** * Sets the minimum number of observations selectable by this component. It * also sets back the currently displayed range to the overall range. * * @param newMinNumberOfObs * any int value. If it is larger than the current range, then * only the whole range is still valid. Otherwise no selection * would be possible anymore. */ public void setMinNumberOfObs(int newMinNumberOfObs) { minNumberOfObs = newMinNumberOfObs; setTSDateRange(enclosingRange); } /** * Sets the currently displayed date range if it conforms to the specified * overall range. This method fires a "TSDateRange" property change with the * old value and the changed value if a new date range was set. * * @param newTSDateRange * the range to be displayed * @throws IllegalArgumentException * if newTSDateRange does not fit in overall range or is * null */ public void setTSDateRange(TSDateRange newTSDateRange) { if (newTSDateRange == null) throw new IllegalArgumentException("Range is null."); String msg; if ((msg = enclosingRange.encloses(newTSDateRange)) != null) throw new IllegalArgumentException(msg); TSDateRange oldDateRange = tSDateRange; tSDateRange = newTSDateRange; String formattedRange = tSDateRange.lowerBound() + ", " + tSDateRange.upperBound(); setTextCarefully(formattedRange); // fire property change if (oldDateRange != null && !oldDateRange.equals(tSDateRange)) firePropertyChange("TSDateRange", oldDateRange, tSDateRange); } /** * Validates input against the TSDateParser and the overall * TSDateRange. It also checks the minimum number of * observations restriction. * * @return error message if failure, null if ok */ public String validateInput() { TSDateRange tmpRange = null; TSDate t1, t2; String inputString = getText().trim(); // Split input in 2 parts, separated by a komma // and parse single date strings afterwards. int kommaIndex = inputString.indexOf(","); if (kommaIndex < 1 || kommaIndex > inputString.length() - 2) // No komma within string, cannot be a valid range. return "Input \"" + inputString + "\" is not a valid date range."; String t1String = inputString.substring(0, kommaIndex); String t2String = inputString.substring(kommaIndex + 1, inputString .length()); try { t1 = TSDate.valueOf(t1String); t2 = TSDate.valueOf(t2String); tmpRange = new TSDateRange(t1, t2); } catch (Throwable ex) { // Something went wrong during parsing or range construction. // Wrong input must be considered exceptional behaviour. String msg = "Input \"" + inputString + "\" is not a valid date range."; log.warn(msg, ex); return msg; } String error = enclosingRange.encloses(tmpRange); // Check also against the minimum number of observations. if (error == null && minNumberOfObs > 0) { // If minNumber exceeds overall number of obs, reduce it. int maxMin = enclosingRange.numOfObs(); int currentMin = (minNumberOfObs > maxMin) ? maxMin : minNumberOfObs; int num = tmpRange.numOfObs(); if (num < currentMin) { String plural = (num == 1) ? "observation" : "observations"; return tmpRange + " contains only " + num + " " + plural + ".\nThis is less than the required minimum of " + currentMin + "."; } } if (error == null) setTSDateRange(tmpRange); return error; } }

Ads help maintain this website.