// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only

/*!
    \title Calendar Widget Example
    \examplecategory {User Interface Components}
    \example widgets/calendarwidget
    \ingroup examples-widgets
    \ingroup examples-layout
    \brief The Calendar Widget example shows use of QCalendarWidget.

    \image calendarwidgetexample.png
           {Calendar widget showing various calendar settings}

    QCalendarWidget displays one calendar month
    at a time and lets the user select a date.
    The calendar consists of four components: a navigation
    bar that lets the user change the month that is
    displayed, a grid where each cell represents one day
    in the month, and two headers that display weekday names
    and week numbers.

    The Calendar Widget example displays a QCalendarWidget and lets the user
    configure its appearance and behavior using
    \l{QComboBox}es, \l{QCheckBox}es, and \l{QDateEdit}s. In
    addition, the user can influence the formatting of individual dates
    and headers.

    The properties of the QCalendarWidget are summarized in the table
    below.

    \table
    \header \li Property
            \li Description
    \row \li \l{QCalendarWidget::}{selectedDate}
         \li The currently selected date.
    \row \li \l{QCalendarWidget::}{minimumDate}
         \li The earliest date that can be selected.
    \row \li \l{QCalendarWidget::}{maximumDate}
         \li The latest date that can be selected.
    \row \li \l{QCalendarWidget::}{firstDayOfWeek}
         \li The day that is displayed as the first day of the week
            (usually Sunday or Monday).
    \row \li \l{QCalendarWidget::}{gridVisible}
         \li Whether the grid should be shown.
    \row \li \l{QCalendarWidget::}{selectionMode}
         \li Whether the user can select a date or not.
    \row \li \l{QCalendarWidget::}{horizontalHeaderFormat}
         \li The format of the day names in the horizontal header
            (e.g., "M", "Mon", or "Monday").
    \row \li \l{QCalendarWidget::}{verticalHeaderFormat}
         \li The format of the vertical header.
    \row \li \l{QCalendarWidget::}{navigationBarVisible}
         \li Whether the navigation bar at the top of the calendar
            widget is shown.
    \endtable

    The example consists of one class, \c Window, which creates and
    lays out the QCalendarWidget and the other widgets that let the
    user configure the QCalendarWidget.

    \section1 Window Class Definition

    Here is the definition of the \c Window class:

    \snippet widgets/calendarwidget/window.h 0
    \dots
    \snippet widgets/calendarwidget/window.h 1

    As is often the case with classes that represent self-contained
    windows, most of the API is private. We will review the private
    members as we stumble upon them in the implementation.

    \section1 Window Class Implementation

    Let's now review the class implementation, starting with the constructor:

    \snippet widgets/calendarwidget/window.cpp 0

    We start by creating the four \l{QGroupBox}es and their child
    widgets (including the QCalendarWidget) using four private \c
    create...GroupBox() functions, described below. Then we arrange
    the group boxes in a QGridLayout.

    We set the grid layout's resize policy to QLayout::SetFixedSize to
    prevent the user from resizing the window. In that mode, the
    window's size is set automatically by QGridLayout based on the
    size hints of its contents widgets.

    To ensure that the window isn't automatically resized every time
    we change a property of the QCalendarWidget (for example, hiding the
    navigation bar, the vertical header, or the grid), we set the
    minimum height of row 0 and the minimum width of column 0 to the
    initial size of the QCalendarWidget.

    Let's move on to the \c createPreviewGroupBox() function:

    \snippet widgets/calendarwidget/window.cpp 9

    The \uicontrol Preview group box contains only one widget: the
    QCalendarWidget. We set it up, connect its
    \l{QCalendarWidget::}{currentPageChanged()} signal to our \c
    reformatCalendarPage() slot to make sure that every new page gets
    the formatting specified by the user.

    The \c createGeneralOptionsGroupBox() function is somewhat large
    and several widgets are set up in the same way. We will look at
    parts of its implementation here and skip the rest:

    \snippet widgets/calendarwidget/window.cpp 10
    \dots

    We start with the setup of the \uicontrol{Week starts on} combobox.
    This combobox controls which day should be displayed as the first
    day of the week.

    The QComboBox class lets us attach user data as a QVariant to
    each item. The data can later be retrieved with QComboBox's
    \l{QComboBox::}{itemData()} function. QVariant doesn't directly
    support the Qt::DayOfWeek data type, but it supports \c int, and
    C++ will happily convert any enum value to \c int.

    \dots
    \snippet widgets/calendarwidget/window.cpp 11
    \dots

    After having created the widgets, we connect the signals and slots. We
    connect the comboboxes to private slots of \c Window or to
    public slots provided by QComboBox.

    \dots
    \snippet widgets/calendarwidget/window.cpp 12

    At the end of the function, we call the slots that update the calendar to ensure
    that the QCalendarWidget is synchronized with the other widgets on startup.

    Let's now take a look at the \c createDatesGroupBox() private function:

    \snippet widgets/calendarwidget/window.cpp 13

    In this function, we create the \uicontrol {Minimum Date}, \uicontrol {Maximum Date},
    and \uicontrol {Current Date} editor widgets,
    which control the calendar's minimum, maximum, and selected dates.
    The calendar's minimum and maximum dates have already been
    set in \c createPrivewGroupBox(); we can then set the widgets
    default values to the calendars values.

    \snippet widgets/calendarwidget/window.cpp 14
    \dots
    \snippet widgets/calendarwidget/window.cpp 15

    We connect the \c currentDateEdit's
    \l{QDateEdit::}{dateChanged()} signal directly to the calendar's
    \l{QCalendarWidget::}{setSelectedDate()} slot. When the calendar's
    selected date changes, either as a result of a user action or
    programmatically, our \c selectedDateChanged() slot updates
    the \uicontrol {Current Date} editor. We also need to react when the user
    changes the \uicontrol{Minimum Date} and \uicontrol{Maximum Date} editors.

    Here is the \c createTextFormatsGroup() function:

    \snippet widgets/calendarwidget/window.cpp 16

    We set up the \uicontrol {Weekday Color} and \uicontrol {Weekend Color} comboboxes
    using \c createColorCombo(), which instantiates a QComboBox and
    populates it with colors ("Red", "Blue", etc.).

    \snippet widgets/calendarwidget/window.cpp 17

    The \uicontrol {Header Text Format} combobox lets the user change the
    text format (bold, italic, or plain) used for horizontal and
    vertical headers. The \uicontrol {First Friday in blue} and \uicontrol {May 1
    in red} check box affect the rendering of specific dates.

    \snippet widgets/calendarwidget/window.cpp 18

    We connect the check boxes and comboboxes to various private
    slots. The \uicontrol {First Friday in blue} and \uicontrol {May 1 in red}
    check boxes are both connected to \c reformatCalendarPage(),
    which is also called when the calendar switches month.

    \dots
    \snippet widgets/calendarwidget/window.cpp 19

    At the end of \c createTextFormatsGroupBox(), we call private
    slots to synchronize the QCalendarWidget with the other widgets.

    We're now done reviewing the four \c create...GroupBox()
    functions. Let's now take a look at the other private functions
    and slots.

    \snippet widgets/calendarwidget/window.cpp 20

    In \c createColorCombo(), we create a combobox and populate it with
    standard colors. The second argument to QComboBox::addItem()
    is a QVariant storing user data (in this case, QColor objects).

    This function was used to set up the \uicontrol {Weekday Color}
    and \uicontrol {Weekend Color} comboboxes.

    \snippet widgets/calendarwidget/window.cpp 1

    When the user changes the \uicontrol {Week starts on} combobox's
    value, \c firstDayChanged() is invoked with the index of the
    combobox's new value. We retrieve the custom data item
    associated with the new current item using
    \l{QComboBox::}{itemData()} and cast it to a Qt::DayOfWeek.

    \c selectionModeChanged(), \c horizontalHeaderChanged(), and \c
    verticalHeaderChanged() are very similar to \c firstDayChanged(),
    so they are omitted.

    \snippet widgets/calendarwidget/window.cpp 2

    The \c selectedDateChanged() updates the \uicontrol{Current Date}
    editor to reflect the current state of the QCalendarWidget.

    \snippet widgets/calendarwidget/window.cpp 3

    When the user changes the minimum date, we tell the
    QCalenderWidget. We also update the \uicontrol {Maximum Date} editor,
    because if the new minimum date is later than the current maximum
    date, QCalendarWidget will automatically adapt its maximum date
    to avoid a contradicting state.

    \snippet widgets/calendarwidget/window.cpp 4

    \c maximumDateChanged() is implemented similarly to \c
    minimumDateChanged().

    \snippet widgets/calendarwidget/window.cpp 5

    Each combobox item has a QColor object as user data corresponding to the
    item's text. After fetching the colors from the comboboxes, we
    set the text format of each day of the week.

    The text format of a column in the calendar is given as a
    QTextCharFormat, which besides the foreground color lets us
    specify various character formatting information. In this
    example, we only show a subset of the possibilities.

    \snippet widgets/calendarwidget/window.cpp 6

    \c weekendFormatChanged() is the same as \c
    weekdayFormatChanged(), except that it affects Saturday and
    Sunday instead of Monday to Friday.

    \snippet widgets/calendarwidget/window.cpp 7

    The \c reformatHeaders() slot is called when the user
    changes the text format of
    the headers. We compare the current text of the \uicontrol {Header Text Format}
    combobox to determine which format to apply. (An alternative would
    have been to store \l{QTextCharFormat} values alongside the combobox
    items.)

    \snippet widgets/calendarwidget/window.cpp 8

    In \c reformatCalendarPage(), we set the text format of the first
    Friday in the month and May 1 in the current year. The text
    formats that are actually used depend on which check boxes are
    checked and what the weekday/weekend formats are.

    QCalendarWidget lets us set the text format of individual dates
    with the \l{QCalendarWidget::}{setDateTextFormat()}. We chose to
    set the date formats when the calendar page changes - i.e. a new month is
    displayed - and when the weekday/weekend format is changed.
    We check which of the \c mayFirstCheckBox and \c firstDayCheckBox, if any,
    are checked and set the text formats accordingly.
*/
