com.google.code.p.gwtchismes.client.GWTCDatePickerAbstract.java Source code

Java tutorial

Introduction

Here is the source code for com.google.code.p.gwtchismes.client.GWTCDatePickerAbstract.java

Source

/*
 * Copyright 2007 Manuel Carrasco Moino. (manuel_carrasco at users.sourceforge.net) 
 * http://code.google.com/p/gwtchismes
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package com.google.code.p.gwtchismes.client;

import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HasHTML;
import com.google.gwt.user.client.ui.HasText;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * <p>
 * <b>Abstract class used for creating complex and customized DatePickers.</b> 
 * </p>
 * @author Manuel Carrasco Moino
 * 
 * <h3>Features</h3>
 * <ul>
 * <li>It can be implemented as a modal and dragable dialog or it can be included into a standard panel.</li>
 * <li>It can be in a decorated box with rounded corners</li>
 * <li>The dialog position is calculated on the fly to avoid be positioned out of the viewport area</li>
 * <li>Display multiple months</li>
 * <li>Month selector menu</li>
 * <li>Configurable restrictions: minimalDate, maximalDate</li>
 * <li>Configurable texts: caption, help and buttons</li>
 * <li>Configurable button style: flat, rounded</li>
 * <li>Configurable button layout (6 rows, 3 at top and 3 at bottom)</li>
 * <li>Uses GWT-i18n for date formating.</li>
 * <li>It extends GWTSimpleDatePicker that has useful methods for date manipulation</li>
 * </ul>
 * 
 * <h3>Example</h3>
 * <pre>
public class GWTCDatePickerCustom extends GWTCDatePickerAbstract {
    
    // You have to call createInstance in the constructor
    public GWTCDatePickerCustom() {
        createInstance(CONFIG_DIALOG | CONFIG_BACKGROUND);
    }
        
    // You have to implement drawDatePickerWidget
    // You can use either configure() or layoutButtons() & layoutCalendar()  
    Override
    void drawDatePickerWidget() {
        int monthsToDisplay = 6;
        int numberOfColumns = 2;
        int monthsIncrement = 6;
        int maxMonthsInMenu = 32;
            
        // Buttons can be placed in any of the 6 availabe rows, 
        // @see com.google.code.p.gwtchismes.client.GWTCDatePickerAbstract#configure() for a detailed explanation.
        String buttonsLayout = "? x;p<m>n";
            
        configure(buttonsLayout, monthsToDisplay, numberOfColumns, monthsIncrement, maxMonthsInMenu);
            
        setMinimalDate(increaseMonth(new Date(), -24));
        setMaximalDate(increaseMonth(new Date(), 24));
        addStyleName("GWTCDatePicker-custom");
    }
}
 * </pre>
 * 
 * <h3>CSS Style Rules</h3>
 * <ul>
 * <li>.GWTCDatePicker { GWTCDatePicket container }</li>
 * <li>.GWTCDatePicker .GWTCDatePicker-help { help dialog } </li>
 * <li>.GWTCDatePicker-dlg { Dependent style when it is a modal dialog } </li>
 * <li>.GWTCDatePicker-no-dlg { Dependent style when it is not placed in a dialog } </li>
 * <li>.GWTCDatePicker-box { Dependent style when it is in a GWTCBox } </li>
 * <li>.GWTCDatePicker-no-box { Dependent style when it is not in a GWTCBox } </li>
 * <li>.GWTCDatePicker .Caption { calendar title }</li>
 * <li>.GWTCDatePicker .panelButtons { panel container with navigation buttons at top }</li>
 * <li>.GWTCDatePicker .panelButtons .buttonsRow_1 { 1st row in top buttons panel  }</li>
 * <li>.GWTCDatePicker .panelButtons .buttonsRow_2 { 2nd row in top buttons panel  }</li>
 * <li>.GWTCDatePicker .panelButtons .buttonsRow_3 { 3th row in top buttons panel  }</li>
 * <li>.GWTCDatePicker .panelButtonsBottom { panel container with navigation buttons at bottom }</li>
 * <li>.GWTCDatePicker .panelButtonsBottom .buttonsRow_1 { 1st row in bottom buttons panel }</li>
 * <li>.GWTCDatePicker .panelButtonsBottom .buttonsRow_2 { 2nd row in bottom buttons panel }</li>
 * <li>.GWTCDatePicker .panelButtonsBottom .buttonsRow_3 { 3th row in bottom buttons panel }</li>
 * 
 * <li>.GWTCDatePicker .panelMonths { container for the displayed months }</li>
 * <li>.GWTCDatePicker .panelMonths .monthLabels { labels with the header of each displayed month }</li>
 * <li>.GWTCDatePicker .panelMonths .monthSeparator { cell between two months }</li>
 * 
 * <li>.GWTCDatePicker-MenuBar { horizontal and vertical menu selector items }</li>
 * <li>.GWTCDatePicker-MenuBar-horizontal { horizontal item of menu selector  }</li>
 * <li>.GWTCDatePicker-MenuBar-vertical { vertical items of menu selector  }</li>
 * </ul>
 * 
 * <h3>Inherited CSS Styles</h3>
 * <ul>
 * <li>.GWTCDatePicker .weekHeader { week headers row}</li>
 * <li>.GWTCDatePicker .weekHeader .cellDayNames { cells with day names} </li>
 * <li>.GWTCDatePicker .panelDays { panel that contains all days }</li>
 * <li>.GWTCDatePicker .panelDays .cellEmpty { cell without days }</li>
 * <li>.GWTCDatePicker .panelDays .cellDays { primary style on each cell that has days }</li>
 * <li>.GWTCDatePicker .panelDays .invalidDay { cell with a day which can not be selected because are out of the allowed interval }</li>
 * <li>.GWTCDatePicker .panelDays .validDay { cell with selectable day }</li>
 * <li>.GWTCDatePicker .panelDays .today { today } </li>
 * <li>.GWTCDatePicker .panelDays .selectedDay { selected day }</li>
 * <li>.GWTCDatePicker .panelDays .afterSelected { days after the selected day and before the maximal day } </li>
 * <li>.GWTCDatePicker .panelDays .beforeSelected { days before the selected day and after the minimal day}</li>
    
 * <li>.GWTCDatePicker-MenuBar .gwt-MenuItem { month selector items }</li>
 * <li>.GWTCDatePicker-MenuBar .gwt-MenuItem-selected { selected month selector items }</li>
 * </ul>
 * 
 */
public abstract class GWTCDatePickerAbstract extends GWTCSimpleDatePicker {

    protected static final String styleName = "GWTCDatePicker";
    protected static final String StyleHelp = styleName + "-help";
    protected static final String StyleDialog = "dialog";
    protected static final String StyleEmbeded = "embeded";
    protected static final String StyleBox = "box";
    protected static final String StyleNoBox = "no-box";

    protected static final String StyleCButtonsTop = "panelButtons";
    protected static final String StyleCButtonsBottom = "panelButtonsBottom";
    protected static final String StyleCButtonsRow = "buttonsRow_";

    protected static final String StyleMonthGrid = "panelMonths";
    protected static final String StyleMonthLabels = "monthLabels";
    protected static final String StyleMonthLabel = "monthLabel";
    protected static final String StyleMonthSeparator = "monthSeparator";
    protected static final String StyleMonthCell = "monthCells";

    static int constant_cont = 0;
    public static final int CONFIG_DEFAULT = constant_cont;
    public static final int CONFIG_DIALOG = (int) Math.pow(2, constant_cont++);
    public static final int CONFIG_ROUNDED_BOX = (int) Math.pow(2, constant_cont++);
    public static final int CONFIG_NO_AUTOHIDE = (int) Math.pow(2, constant_cont++);
    public static final int CONFIG_NO_ANIMATION = (int) Math.pow(2, constant_cont++);
    public static final int CONFIG_BACKGROUND = (int) Math.pow(2, constant_cont++);
    public static final int CONFIG_FLAT_BUTTONS = (int) Math.pow(2, constant_cont++);
    public static final int CONFIG_STANDARD_BUTTONS = (int) Math.pow(2, constant_cont++);

    public static final String MONTH_FORMAT = "MMMM, yyyy";

    protected GWTCAlert helpDlg = new GWTCAlert(GWTCAlert.OPTION_ROUNDED_BLUE);

    protected String helpStr = "Calendar-Picker is a component of GWTChismes library.\n"
            + "(c) Manuel Carrasco 2007\n" + "http://code.google.com/p/gwtchismes\n\n" + "Navigation buttons:\n"
            + "\u003c Previous Month\n" + "\u003e Next Month\n" + "\u00AB Previous Year\n" + "\u00BB Next Year\n"
            + "- Actual Month\n" + "x Close\n ";

    // Containers
    protected GWTCModalBox calendarDlg = null;
    protected Panel outer;

    // Dates panel
    protected final FlexTable calendarGrid = new FlexTable();

    // Navigation Buttons
    protected final DockPanel navButtonsTop = new DockPanel();
    protected final DockPanel navButtonsBottom = new DockPanel();
    protected final DockPanel topButtonsRow1 = new DockPanel();
    protected final DockPanel topButtonsRow0 = new DockPanel();
    protected final DockPanel topButtonsRow2 = new DockPanel();
    protected final DockPanel bottomButtonsRow0 = new DockPanel();
    protected final DockPanel bottomButtonsRow1 = new DockPanel();
    protected final DockPanel bottomButtonsRow2 = new DockPanel();
    protected final DockPanel leftButtons = new DockPanel();
    protected final DockPanel rightButtons = new DockPanel();
    protected Button helpBtn;
    protected Button closeBtn;
    protected Button todayBtn;
    protected Button prevMBtn;
    protected Button prevYBtn;
    protected Button nextMBtn;
    protected Button nextYBtn;

    // Month selector menu
    MenuBar monthSelectorHeader = new MenuBar();
    Vector<Label> monthHeaders = new Vector<Label>();
    protected MenuBar monthMenu = new MenuBar(true);

    // Vector of montly datepickers to display
    Vector<GWTCSimpleDatePicker> simpleDatePickers = new Vector<GWTCSimpleDatePicker>();

    // Configuration parameters
    protected int monthColumns = 3;
    protected int monthSelector = 12;
    protected int monthStep = 1;
    private boolean showWeekNumbers = false;
    private boolean clickOnWeekNumbers = false;

    /**
     * Classes implementing this abstract class, have to implement this method
     */
    protected abstract void drawDatePickerWidget();

    /**
     * Creates the calendar instance based in the configuration provided. 
     * 
     * Options can be passed joining these using the or bit wise operator
     * <ul>
     * <li>CONFIG_DIALOG            show as modal dialog</li>
     * <li>CONFIG_ROUNDED_BOX       wrap with a rounded-corner box</li>
     * <li>CONFIG_NO_AUTOHIDE       don't autohide dialog when the user click out of the picker</li>
     * <li>CONFIG_NO_ANIMATION      don't animate the dialog box when it is showed/hidden</li>
     * <li>CONFIG_NO_ANIMATION      don't animate the dialog box when it is showed/hidden</li>
     * <li>CONFIG_BACKGROUND        show a semitransparent background covering all the document</li>
     * <li>CONFIG_FLAT_BUTTONS      use native Buttons instead of GWTCButton also add the dependent class 'flat'</li>
     * <li>CONFIG_STANDARD_BUTTONS  use native browser Buttons instead of GWTCButton</li>
     * </ul>
     */
    public void initialize(int config) {

        int buttonsType = config & CONFIG_FLAT_BUTTONS | config & CONFIG_STANDARD_BUTTONS;
        helpBtn = createButton(buttonsType, "?", this);
        closeBtn = createButton(buttonsType, "x", this);
        todayBtn = createButton(buttonsType, "-", this);
        prevMBtn = createButton(buttonsType, "\u003c", this);
        prevYBtn = createButton(buttonsType, "\u00AB", this);
        nextMBtn = createButton(buttonsType, "\u003e", this);
        nextYBtn = createButton(buttonsType, "\u00BB", this);

        if ((config & CONFIG_DIALOG) == CONFIG_DIALOG) {
            int opt = 0;
            if ((config & CONFIG_ROUNDED_BOX) == CONFIG_ROUNDED_BOX) {
                opt |= GWTCModalBox.OPTION_ROUNDED_FLAT;
            }
            if ((config & CONFIG_BACKGROUND) != CONFIG_BACKGROUND) {
                opt |= GWTCModalBox.OPTION_DISABLE_BACKGROUND;
                if ((config & CONFIG_NO_AUTOHIDE) == CONFIG_NO_AUTOHIDE) {
                    opt |= GWTCModalBox.OPTION_DISABLE_AUTOHIDE;
                }
            }
            calendarDlg = new GWTCModalBox(opt);
            calendarDlg.setAnimationEnabled((config & CONFIG_NO_ANIMATION) != CONFIG_NO_ANIMATION);

            outer = calendarDlg;
            initWidget(new DockPanel());

            setStyleName(styleName);
            addStyleDependentName(StyleDialog);
            setZIndex(999);
        } else {
            if ((config & CONFIG_ROUNDED_BOX) == CONFIG_ROUNDED_BOX) {
                outer = new GWTCBox(GWTCBox.STYLE_FLAT);
            } else {
                outer = new VerticalPanel();
            }
            String s = outer.getStyleName();
            initWidget(outer);
            setStyleName(styleName);
            addStyleDependentName(StyleEmbeded);
            if (s != null && s.length() > 0)
                addStyleName(s);
        }

        helpDlg.addStyleName(StyleHelp);
        navButtonsTop.setStyleName(StyleCButtonsTop);
        navButtonsBottom.setStyleName(StyleCButtonsBottom);
        calendarGrid.setStyleName(StyleMonthGrid);
        navButtonsTop.setWidth("100%");
        calendarGrid.setWidth("100%");
        navButtonsBottom.setWidth("100%");

        if ((config & CONFIG_ROUNDED_BOX) == CONFIG_ROUNDED_BOX)
            addStyleDependentName(StyleBox);
        else
            addStyleDependentName(StyleNoBox);

        if ((config & CONFIG_DIALOG) != CONFIG_DIALOG)
            closeBtn.setVisible(false);

        monthSelectorHeader.setAnimationEnabled(true);

        outer.add(navButtonsTop);
        outer.add(calendarGrid);
        outer.add(navButtonsBottom);

        drawDatePickerWidget();
        refresh();

        DOM.sinkEvents(outer.getElement(), Event.ONMOUSEOVER | Event.ONMOUSEOUT | Event.ONCLICK);
        DOM.setStyleAttribute(outer.getElement(), "cursor", "default");
        DOM.setElementAttribute(monthMenu.getElement(), "align", "center");
    }

    /**
     * 
     * Configure this calendarPicker.
     * 
     * 
     * @param buttonsLayout   a string representation with the disposition of buttons.<br/>
     *      There are 6 rows of buttons, 3 at top and 3 at bottom.<br/>
     *      Each row has to be separated by the ';' character.<br/>
     *      Available buttons are:<br/>
     *       help(?), close(x), nextMonth(>), previowusMonsh(<), nextYear(n), prevYear(p)<br/>
     *       monthMenu(m), today(-), empty(space)<br/>
     *    
     * @param months            number of months to display
     * @param monthsPerRow      number of month columns
     * @param monthsStep        number of months to jump when the buttons > or < are pushed
     * @param monthsInSelector  number of items (months) in the months selector menu. 
     */
    public void configure(String buttonsLayout, int months, int monthsPerRow, int monthsStep,
            int monthsInSelector) {
        monthColumns = monthsPerRow;
        monthSelector = monthsInSelector;
        monthStep = monthsStep;
        setNumberOfMonths(months);

        monthSelectorHeader.removeFromParent();

        layoutButtons(buttonsLayout);
        layoutCalendar();
        refresh();
    }

    protected void setNumberOfMonths(int months) {
        monthColumns = Math.min(monthColumns, months);
        monthStep = Math.min(monthStep, months);
        simpleDatePickers = new Vector<GWTCSimpleDatePicker>();

        for (int i = 0; i < Math.max(1, months); i++) {
            GWTCSimpleDatePicker picker = new GWTCSimpleDatePicker(true);
            picker.showWeekNumbers(showWeekNumbers);
            picker.clickOnWeekNumbers(clickOnWeekNumbers);
            simpleDatePickers.add(picker);
            Label l = new Label();
            DOM.setElementAttribute(l.getElement(), "align", "center");
            monthHeaders.add(l);
        }
        setMinimalDate(super.getMinimalDate());
        setMaximalDate(super.getMaximalDate());
        setSelectedDate(super.getSelectedDate());
    }

    private Widget getButton(String s, int pos) {
        if (pos < s.length()) {
            int c = s.charAt(pos);
            if (c == '_' || c == ' ')
                return new Label(" ");
            if (c == 'x')
                return closeBtn;
            if (c == '?')
                return helpBtn;
            if (c == '-')
                return todayBtn;
            if (c == '>')
                return nextMBtn;
            if (c == '<')
                return prevMBtn;
            if (c == 'n')
                return nextYBtn;
            if (c == 'p')
                return prevYBtn;
            if (c == 'm')
                return monthSelectorHeader;
        }
        return null;
    }

    protected void layoutButtons(String distribution) {
        navButtonsBottom.clear();
        navButtonsTop.clear();
        DockPanel[] panels = { topButtonsRow0, topButtonsRow1, topButtonsRow2, bottomButtonsRow0, bottomButtonsRow1,
                bottomButtonsRow2, leftButtons, rightButtons };
        String s[] = distribution.split("[;:,]");

        Widget w = null, m = null;
        for (int i = 0; i < panels.length && i < s.length; i++) {
            DockPanel p = panels[i];
            p.clear();

            if (s[i].length() == 0)
                continue;

            for (int j = 0; j < s[i].length(); j++) {
                if ((w = getButton(s[i], j)) != null) {
                    p.add(w, p != rightButtons ? DockPanel.WEST : DockPanel.EAST);
                }
                if (j == s[i].length() / 2)
                    m = w;
            }

            if (!p.iterator().hasNext())
                continue;

            p.setWidth("100%");
            if (p != leftButtons && p != rightButtons) {
                if (m != null) {
                    p.setCellWidth(m, "100%");
                    m.setWidth("100%");
                }
            }
            if (i < 3)
                navButtonsTop.add(p, DockPanel.NORTH);
            else if (i < 6)
                navButtonsBottom.add(p, DockPanel.NORTH);

            if (i < 6)
                p.addStyleName(StyleCButtonsRow + (i % 3));
        }
    }

    protected void layoutCalendar() {
        calendarGrid.clear();
        calendarGrid.setCellSpacing(0);
        for (int i = 0, row = -2, col = 0; i < simpleDatePickers.size(); i++) {
            if ((i % monthColumns) == 0) {
                col = 0;
                row += 2;
            } else if (i > 0) {
                calendarGrid.setHTML(row, col, "&nbsp;");
                calendarGrid.setHTML(row + 1, col, "&nbsp;");
                calendarGrid.getCellFormatter().addStyleName(row, col, StyleMonthSeparator);
                calendarGrid.getCellFormatter().addStyleName(row + 1, col, StyleMonthSeparator);
                col += 1;
            }

            if (monthSelectorHeader.getParent() == null || simpleDatePickers.size() > 1) {
                if (i == 0 || (i % monthColumns) == 0) {
                    calendarGrid.getRowFormatter().addStyleName(row, StyleMonthLabels);
                    calendarGrid.getRowFormatter().addStyleName(row + 1, StyleMonthCell);
                }
                Widget w = null;
                if (i == 0 && monthSelectorHeader.getElement().getParentElement() == null)
                    w = monthSelectorHeader;
                //calendarGrid.setWidget(row, col, monthSelectorHeader);
                else
                    w = monthHeaders.get(i);
                //calendarGrid.setWidget(row, col, monthHeaders.get(i));

                DockPanel p = null;
                if (leftButtons.iterator().hasNext() && leftButtons.getParent() == null && col == 0) {
                    p = leftButtons;
                    p.add(w, DockPanel.WEST);
                    p.setCellWidth(w, "100%");
                    w = p;
                    if (simpleDatePickers.size() == 1) {
                        Iterator<Widget> it = p.iterator();
                        while (it.hasNext()) {
                            p.add(it.next(), DockPanel.WEST);
                        }
                    }
                }
                if (rightButtons.iterator().hasNext() && rightButtons.getParent() == null
                        && ((i + 1) % monthColumns) == 0) {
                    p = rightButtons;
                    p.add(w, DockPanel.WEST);
                    p.setCellWidth(w, "100%");
                    w = p;
                }
                calendarGrid.setWidget(row, col, w);
            }

            calendarGrid.setWidget(row + 1, col, simpleDatePickers.get(i));
            calendarGrid.getColumnFormatter().addStyleName(i, "Month-" + i);
            simpleDatePickers.get(i).addValueChangeHandler(onDaySelected);
            col++;
        }
    }

    /**
     * Redraw all calendar elements into the container
     */
    @Override
    public void refresh() {
        needsRedraw = false;
        prevMBtn.setEnabled(simpleDatePickers.get(0).isVisibleMonth(-1));
        nextMBtn.setEnabled(simpleDatePickers.get(0).isVisibleMonth(1));
        prevYBtn.setEnabled(simpleDatePickers.get(0).isVisibleMonth(-1));
        nextYBtn.setEnabled(simpleDatePickers.get(0).isVisibleMonth(1));
        todayBtn.setEnabled(getMonthNumber(simpleDatePickers.get(0).getCursorDate()) != getMonthNumber(new Date()));
        fillMenuItems();
        for (int i = 0; i < simpleDatePickers.size(); i++) {
            simpleDatePickers.get(i)
                    .setCursorDate(GWTCSimpleDatePicker.increaseMonth(simpleDatePickers.get(0).getCursorDate(), i));
            simpleDatePickers.get(i).refresh();
            monthHeaders.get(i).setText(
                    GWTCSimpleDatePicker.formatDate(MONTH_FORMAT, simpleDatePickers.get(i).getCursorDate()));
        }
    }

    private void fillMenuItems() {
        monthSelectorHeader.clearItems();
        monthMenu.clearItems();
        monthSelectorHeader.addItem(
                GWTCSimpleDatePicker.formatDate(MONTH_FORMAT, simpleDatePickers.get(0).getCursorDate()), monthMenu);

        int n = -1 * (monthSelector / 2);
        Date d = new Date(GWTCSimpleDatePicker.getFirstDayOfMonth(getCursorDate()).getTime());
        Date md = new Date(
                GWTCSimpleDatePicker.getFirstDayOfMonth(simpleDatePickers.get(0).getMinimalDate()).getTime());
        d = GWTCSimpleDatePicker.increaseMonth(d, n);
        while (GWTCSimpleDatePicker.compareDate(md, d) < 0) {
            d = GWTCSimpleDatePicker.increaseMonth(d, 1);
            n++;
        }
        n += monthSelector;
        d = GWTCSimpleDatePicker.increaseMonth(getCursorDate(), n);
        while (GWTCSimpleDatePicker.compareDate(simpleDatePickers.get(0).getMaximalDate(), d) > 0) {
            d = GWTCSimpleDatePicker.increaseMonth(d, -1);
            n--;
        }
        n -= monthSelector;
        d = GWTCSimpleDatePicker.increaseMonth(getCursorDate(), n);
        for (int i = n; i < monthSelector; i++) {
            String t = GWTCSimpleDatePicker.formatDate(MONTH_FORMAT, d);
            MenuCommand c = new MenuCommand(d);
            d = GWTCSimpleDatePicker.increaseMonth(d, 1);
            if (GWTCSimpleDatePicker.compareDate(d, simpleDatePickers.get(0).getMaximalDate()) >= 0
                    && GWTCSimpleDatePicker.compareDate(simpleDatePickers.get(0).getMinimalDate(), d) > 0) {
                monthMenu.addItem(t, c);
            }
        }

    }

    public static void internationalize(Widget b, Map<String, String> strs, String ktext) {
        if (strs == null)
            return;
        String text = strs.get(ktext);
        String title = strs.get(ktext + ".title");
        if (text != null && text.length() > 0) {
            if (b instanceof HasHTML)
                ((HasHTML) b).setText(text);
            else if (b instanceof HasText)
                ((HasText) b).setText(text);
            else if (b instanceof GWTCDatePickerAbstract)
                ((GWTCDatePickerAbstract) b).setCaptionText(text);
            else
                System.out.println(
                        "GWTCDatePickerAbstract.internationalize: unknown element " + b + " " + ktext + " " + text);
        }
        if (title != null && title.length() > 0)
            b.setTitle(title);
    }

    public void setI18nMessages(Map<String, String> strs) {
        internationalize(nextMBtn, strs, "key.next.month");
        internationalize(prevMBtn, strs, "key.prev.month");
        internationalize(nextYBtn, strs, "key.next.year");
        internationalize(prevYBtn, strs, "key.prev.year");
        internationalize(todayBtn, strs, "key.today");
        internationalize(helpBtn, strs, "key.help");
        internationalize(closeBtn, strs, "key.close");

        String help = strs.get("key.calendar.help");
        if (help != null && help.length() > 0)
            helpStr = help;

        String caption = strs.get("key.caption");
        if (caption != null)
            setText(caption);
    }

    /**
     * Set the text for the caption of the dialog box. It is only available if the calendar is shown as a dialog.
     * 
     * @param t
     *            the message to display
     */
    public void setCaptionText(String t) {
        if (calendarDlg != null)
            calendarDlg.setText(t);
    }

    /**
     * @deprecated
     */
    public void setText(String t) {
        setCaptionText(t);
    }

    /* (non-Javadoc)
     * @see com.google.gwt.user.client.ui.UIObject#setStyleName(java.lang.String)
     */
    @Override
    public void setStyleName(String s) {
        if (calendarDlg != null)
            calendarDlg.setStyleName(s);
        else
            outer.setStyleName(s);

        monthSelectorHeader.setStyleName(s + "-MenuBar");
        monthMenu.setStyleName(s + "-MenuBar");
        monthSelectorHeader.addStyleName(s + "-MenuBar-horizontal");
        monthMenu.addStyleName(s + "-MenuBar-vertical");
        for (int i = 0; i < monthHeaders.size(); i++) {
            monthHeaders.get(i).setStyleName(StyleMonthLabel);
            monthHeaders.get(i).addStyleName(s + "-MenuBar");
            monthSelectorHeader.addStyleName(s + "-MenuBar-horizontal");
        }
        if (!s.equals(styleName)) {
            addStyleName(styleName);
        }
    }

    /* (non-Javadoc)
     * @see com.google.gwt.user.client.ui.UIObject#addStyleName(java.lang.String)
     */
    @Override
    public void addStyleName(String s) {
        if (calendarDlg != null) {
            calendarDlg.addStyleName(s);
        } else {
            outer.addStyleName(s);
        }
        addStyleToMonthMenu(s);
    }

    private void addStyleToMonthMenu(String s) {
        monthSelectorHeader.addStyleName(s + "-MenuBar");
        monthMenu.addStyleName(s + "-MenuBar");
        monthSelectorHeader.addStyleName(s + "-MenuBar-horizontal");
        monthMenu.addStyleName(s + "-MenuBar-vertical");
        for (int i = 0; i < monthHeaders.size(); i++) {
            monthHeaders.get(i).addStyleName(s + "-MenuBar");
        }
    }

    /* (non-Javadoc)
     * @see com.google.gwt.user.client.ui.UIObject#addStyleDependentName(java.lang.String)
     */
    @Override
    public void addStyleDependentName(String s) {
        if (calendarDlg != null)
            calendarDlg.addStyleDependentName(s);
        else
            outer.addStyleDependentName(s);

        addStyleToMonthMenu(getStylePrimaryName() + "-" + s);
    }

    /* (non-Javadoc)
     * @see com.google.gwt.user.client.ui.UIObject#getStyleName()
     */
    @Override
    public String getStyleName() {
        return calendarDlg != null ? calendarDlg.getStyleName() : outer.getStyleName();
    }

    /* (non-Javadoc)
     * @see com.google.gwt.user.client.ui.UIObject#getStylePrimaryName()
     */
    @Override
    public String getStylePrimaryName() {
        return calendarDlg != null ? calendarDlg.getStylePrimaryName() : outer.getStylePrimaryName();
    }

    /* (non-Javadoc)
     * @see com.google.gwt.user.client.ui.UIObject#getElement()
     */
    @Override
    public Element getElement() {
        return calendarDlg != null ? calendarDlg.getElement() : outer.getElement();
    }

    /* (non-Javadoc)
     * @see com.google.code.p.gwtchismes.client.GWTCSimpleDatePicker#getCursorDate()
     */
    @Override
    public Date getCursorDate() {
        return simpleDatePickers.get(0).getCursorDate();
    }

    /* (non-Javadoc)
     * @see com.google.gwt.user.client.ui.Composite#onAttach()
     */
    @Override
    protected void onAttach() {
        super.onAttach();
    }

    ValueChangeHandler<GWTCSimpleDatePicker> onDaySelected = new ValueChangeHandler<GWTCSimpleDatePicker>() {
        public void onValueChange(ValueChangeEvent<GWTCSimpleDatePicker> event) {
            setSelectedDate(event.getValue().getSelectedDate());
        }
    };

    /**
    * Show the calendar container.
    *  
    * If element is not null the dialog is positioned near of it, 
    * otherwise it is centered on the viewport
    * 
    */
    public void show(Widget w) {
        if (w != null)
            show(DOM.getAbsoluteLeft(w.getElement()), DOM.getAbsoluteTop(w.getElement()));
        else
            center();
    }

    /**
    * Show the calendar container besides the element passed as argument
    *  
    */
    public void showBesidesElement(Element e) {
        if (e != null)
            show(DOM.getAbsoluteLeft(e), DOM.getAbsoluteTop(e));
        else
            center();
    }

    /**
    * Show the calendar container centered in the document panel
    *  
    */

    public void center() {
        show(-1, -1);

    }

    /**
     * Show the calendar container, and positione it in the provided coordinates.
     */
    public void show(int left, int top) {
        if (needsRedraw)
            refresh();

        if (calendarDlg == null) {
            assert outer
                    .isAttached() : "Calendar has not been attached, even though it is not configured as a popup.";
            outer.setVisible(true);
        } else {
            if (top >= 0 && left >= 0) {
                calendarDlg.setPopupPosition(left, top);
                calendarDlg.show();
                moveIntoVisibleArea();
                DOM.scrollIntoView(calendarGrid.getElement());
            } else {
                calendarDlg.center();
            }
        }
        todayBtn.setFocus(true);
    }

    /* (non-Javadoc)
     * @see com.google.code.p.gwtchismes.client.GWTCSimpleDatePicker#show()
     */
    @Override
    public void show() {
        center();
    }

    /**
     * Set the zIndex value.
     * 
     * @param z
     */
    public void setZIndex(int z) {
        if (calendarDlg != null) {
            DOM.setStyleAttribute(calendarDlg.getElement(), "zIndex", String.valueOf(z));
            helpDlg.setZIndex(z + 1);
        }
    }

    int max = 0;

    private void moveIntoVisibleArea() {
        if (calendarDlg != null) {
            int w = Window.getClientWidth() + Window.getScrollLeft();
            int xd = calendarDlg.getAbsoluteLeft();
            int wd = calendarGrid.getOffsetWidth() + 40;
            if ((xd + wd) > w) {
                xd = xd - ((xd + wd) - w);
            }

            int h = Window.getClientHeight() + Window.getScrollTop();
            int yd = calendarDlg.getAbsoluteTop();
            int hd = calendarDlg.getOffsetHeight() + 20;
            if ((yd + hd) > h) {
                yd = yd - ((yd + hd) - h);
            }
            calendarDlg.setPopupPosition(xd, yd);
        }
    }

    /**
     * Hide the calendar container.
     */
    public void hide() {
        if (calendarDlg != null) {
            calendarDlg.hide();
        } else
            outer.setVisible(false);
    }

    /* (non-Javadoc)
     * @see com.google.code.p.gwtchismes.client.GWTCSimpleDatePicker#setCursorDate(java.util.Date)
     */
    @Override
    public void setCursorDate(Date d) {
        super.setCursorDate(d);
        simpleDatePickers.get(0).setCursorDate(d);
    }

    /* (non-Javadoc)
     * @see com.google.code.p.gwtchismes.client.GWTCSimpleDatePicker#setSelectedDate(java.util.Date)
     */
    @Override
    public void setSelectedDate(Date d) {
        super.setSelectedDate(d);
        if (d == null)
            return;
        for (int i = 0; i < simpleDatePickers.size(); i++) {
            simpleDatePickers.get(i).setSelectedDate(d);
            simpleDatePickers.get(i).refresh();
        }
    }

    @Override
    public void showWeekNumbers(boolean b) {
        this.showWeekNumbers = b;
        for (int i = 0; i < simpleDatePickers.size(); i++) {
            simpleDatePickers.get(i).showWeekNumbers(b);
            simpleDatePickers.get(i).refresh();
        }
    }

    @Override
    public void clickOnWeekNumbers(boolean b) {
        this.clickOnWeekNumbers = b;
        for (int i = 0; i < simpleDatePickers.size(); i++) {
            simpleDatePickers.get(i).clickOnWeekNumbers(b);
        }
    }

    /* (non-Javadoc)
     * @see com.google.code.p.gwtchismes.client.GWTCSimpleDatePicker#setMinimalDate(java.util.Date)
     */
    @Override
    public void setMinimalDate(Date d) {
        super.setMinimalDate(d);
        for (int i = 0; i < simpleDatePickers.size(); i++)
            simpleDatePickers.get(i).setMinimalDate(d);
    }

    /* (non-Javadoc)
     * @see com.google.code.p.gwtchismes.client.GWTCSimpleDatePicker#setMaximalDate(java.util.Date)
     */
    @Override
    public void setMaximalDate(Date d) {
        super.setMaximalDate(d);
        for (int i = 0; i < simpleDatePickers.size(); i++)
            simpleDatePickers.get(i).setMaximalDate(d);
    }

    /* (non-Javadoc)
     * @see com.google.code.p.gwtchismes.client.GWTCSimpleDatePicker#getSelectedDate()
     */
    @Override
    public Date getSelectedDate() {
        return simpleDatePickers.get(0).getSelectedDate();
    }

    private int isMonthInRange(int incr) {
        while (incr != 0 && !simpleDatePickers.get(0).isVisibleMonth(incr))
            incr = incr < 0 ? incr + 1 : incr - 1;
        return incr;
    }

    @Override
    public void onClick(ClickEvent event) {
        Widget sender = (Widget) event.getSource();
        if (prevMBtn.equals(sender)) {
            setCursorDate(GWTCSimpleDatePicker.increaseMonth(getCursorDate(), isMonthInRange(-1 * monthStep)));
        } else if (nextMBtn.equals(sender)) {
            setCursorDate(GWTCSimpleDatePicker.increaseMonth(getCursorDate(), isMonthInRange(monthStep)));
        } else if (prevYBtn.equals(sender)) {
            setCursorDate(GWTCSimpleDatePicker.increaseMonth(getCursorDate(), isMonthInRange(-12)));
        } else if (nextYBtn.equals(sender)) {
            setCursorDate(GWTCSimpleDatePicker.increaseMonth(getCursorDate(), isMonthInRange(12)));
        } else if (todayBtn.equals(sender)) {
            setCursorDate(new Date());
        } else if (helpBtn.equals(sender)) {
            helpDlg.alert(helpStr.replaceAll("\\n", "<br/>"));
        } else if (closeBtn.equals(sender)) {
            hide();
        } else {
            super.onClick(event);
        }
        refresh();
    }

    @Override
    public HandlerRegistration addValueChangeHandler(final ValueChangeHandler<GWTCSimpleDatePicker> handler) {
        for (int i = 0; i < simpleDatePickers.size(); i++) {
            simpleDatePickers.get(i).addValueChangeHandler(handler);
        }
        return new HandlerRegistration() {
            public void removeHandler() {
                for (int i = 0; i < simpleDatePickers.size(); i++) {
                    simpleDatePickers.get(i).removeValueChangeHandler(handler);
                }
            }
        };
    }

    private Button createButton(int buttonsType, String text, ClickHandler clickHandler) {
        Button b;
        if (buttonsType == CONFIG_DEFAULT)
            b = new GWTCButton();
        else
            b = new GWTCButton(GWTCButton.BUTTON_TYPE_0, "");

        if (buttonsType == CONFIG_FLAT_BUTTONS)
            b.addStyleDependentName("flat");

        if (clickHandler != null)
            b.addClickHandler(clickHandler);

        b.setText(text);
        return b;
    }

    class MenuCommand implements Command {
        Date date;

        public MenuCommand(Date d) {
            date = d;
        }

        public void execute() {
            setCursorDate(date);
            refresh();
        }
    }

}