Warning, /plasma/plasma-workspace/components/calendar/qml/MonthView.qml is written in an unsupported language. File is not indexed.

0001 /*
0002     SPDX-FileCopyrightText: 2013 Heena Mahour <heena393@gmail.com>
0003     SPDX-FileCopyrightText: 2013 Sebastian Kügler <sebas@kde.org>
0004     SPDX-FileCopyrightText: 2015 Kai Uwe Broulik <kde@privat.broulik.de>
0005     SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 import QtQuick 2.15
0010 import QtQuick.Layouts 1.1
0011 
0012 import org.kde.plasma.workspace.calendar 2.0
0013 import org.kde.plasma.components 3.0 as PlasmaComponents3
0014 
0015 Item {
0016     id: root
0017 
0018     /**
0019      * Currently selected month name.
0020      * \property string MonthView::selectedMonth
0021      */
0022     property alias selectedMonth: calendarBackend.monthName
0023     /**
0024      * Currently selected month year.
0025      * \property int MonthView::selectedYear
0026      */
0027     property alias selectedYear: calendarBackend.year
0028     /**
0029      * The start day of a week.
0030      * \property int MonthView::firstDayOfWeek
0031      * \sa Calendar::firstDayOfWeek
0032      */
0033     property alias firstDayOfWeek: calendarBackend.firstDayOfWeek
0034     /**
0035      * The event plugins manager used in the view
0036      */
0037     property QtObject eventPluginsManager
0038 
0039     property QtObject date
0040     property date currentDate
0041     property string todayAuxilliaryText: ""
0042     // Bind to todayAuxilliaryText so sublabel can be visible on debut
0043     property string currentDateAuxilliaryText: todayAuxilliaryText
0044 
0045     property date showDate: new Date()
0046 
0047     property int borderWidth: 1
0048     property real borderOpacity: 0.4
0049 
0050     property int columns: calendarBackend.days
0051     property int rows: calendarBackend.weeks
0052 
0053     property Item selectedItem
0054     property int week;
0055     property int firstDay: new Date(showDate.getFullYear(), showDate.getMonth(), 1).getDay()
0056     property alias today: calendarBackend.today
0057     property bool showWeekNumbers: false
0058 
0059     // properties for communicating with the digital clock applet
0060     property bool showDigitalClockHeader: false
0061     property var digitalClock: null
0062     property var eventButton: null
0063     property alias viewHeader: viewHeader
0064 
0065     /**
0066      * SwipeView currentIndex needed for binding a TabBar to the MonthView.
0067      */
0068     property alias currentIndex: swipeView.currentIndex
0069 
0070     property alias cellHeight: mainDaysCalendar.cellHeight
0071     property QtObject daysModel: calendarBackend.daysModel
0072 
0073     KeyNavigation.up: viewHeader.previousButton
0074     // The view can have no highlighted item, so always highlight the first item
0075     Keys.onDownPressed: swipeView.currentItem.focusFirstCellOfView()
0076 
0077     function isToday(date) {
0078         return date.toDateString() === new Date().toDateString();
0079     }
0080 
0081     function eventDate(yearNumber,monthNumber,dayNumber) {
0082         const d = new Date(yearNumber, monthNumber-1, dayNumber);
0083         return Qt.formatDate(d, "dddd dd MMM yyyy");
0084     }
0085 
0086     function updateYearOverview() {
0087         const date = calendarBackend.displayedDate;
0088         const day = date.getDate();
0089         const year = date.getFullYear();
0090 
0091         for (let i = 0, j = monthModel.count; i < j; ++i) {
0092             monthModel.setProperty(i, "yearNumber", year);
0093         }
0094     }
0095 
0096     function updateDecadeOverview() {
0097         const date = calendarBackend.displayedDate;
0098         const day = date.getDate();
0099         const month = date.getMonth() + 1;
0100         const year = date.getFullYear();
0101         const decade = year - year % 10;
0102 
0103         for (let i = 0, j = yearModel.count; i < j; ++i) {
0104             const label = decade - 1 + i;
0105             yearModel.setProperty(i, "yearNumber", label);
0106             yearModel.setProperty(i, "label", label);
0107         }
0108     }
0109 
0110     /**
0111      * Possible calendar views
0112      */
0113     enum CalendarView {
0114         DayView,
0115         MonthView,
0116         YearView
0117     }
0118 
0119     /**
0120      * Move calendar to month view showing today's date.
0121      */
0122     function resetToToday() {
0123         calendarBackend.resetToToday();
0124         root.currentDate = root.today;
0125         root.currentDateAuxilliaryText = root.todayAuxilliaryText;
0126         swipeView.currentIndex = 0;
0127     }
0128 
0129     /**
0130      * Go to the next month/year/decade depending on the current
0131      * calendar view displayed.
0132      */
0133     function nextView() {
0134         swipeView.currentItem.resetViewPosition();
0135         swipeView.currentItem.incrementCurrentIndex();
0136     }
0137 
0138     /**
0139      * Go to the previous month/year/decade depending on the current
0140      * calendar view displayed.
0141      */
0142     function previousView() {
0143         swipeView.currentItem.resetViewPosition();
0144         swipeView.currentItem.decrementCurrentIndex();
0145     }
0146 
0147     /**
0148      * \return CalendarView
0149      */
0150     readonly property var calendarViewDisplayed: {
0151         if (swipeView.currentIndex === 0) {
0152             return MonthView.CalendarView.DayView;
0153         } else if (swipeView.currentIndex === 1) {
0154             return MonthView.CalendarView.MonthView;
0155         } else if (swipeView.currentIndex === 2) {
0156             return MonthView.CalendarView.YearView;
0157         }
0158     }
0159 
0160     /**
0161      * Show month view.
0162      */
0163     function showMonthView() {
0164         swipeView.currentIndex = 0;
0165     }
0166 
0167     /**
0168      * Show year view.
0169      */
0170     function showYearView() {
0171         swipeView.currentIndex = 1;
0172     }
0173 
0174     /**
0175      * Show decade view.
0176      */
0177     function showDecadeView() {
0178         swipeView.currentIndex = 2;
0179     }
0180 
0181     Connections {
0182         target: eventPluginsManager
0183         function onPluginsChanged() {
0184             root.todayAuxilliaryText = "";
0185         }
0186     }
0187 
0188     Calendar {
0189         id: calendarBackend
0190 
0191         days: 7
0192         weeks: 6
0193         firstDayOfWeek: Qt.locale().firstDayOfWeek
0194         today: root.today
0195 
0196         Component.onCompleted: {
0197             daysModel.setPluginsManager(root.eventPluginsManager);
0198         }
0199 
0200         onYearChanged: {
0201             updateYearOverview()
0202             updateDecadeOverview()
0203         }
0204     }
0205 
0206     ListModel {
0207         id: monthModel
0208 
0209         Component.onCompleted: {
0210             for (let i = 0; i < 12; ++i) {
0211                 append({
0212                     label: Qt.locale(Qt.locale().uiLanguages[0]).standaloneMonthName(i, Locale.LongFormat),
0213                     monthNumber: i + 1,
0214                     yearNumber: 2050,
0215                     isCurrent: true
0216                 })
0217             }
0218             updateYearOverview()
0219         }
0220     }
0221 
0222     ListModel {
0223         id: yearModel
0224 
0225         Component.onCompleted: {
0226             for (let i = 0; i < 12; ++i) {
0227                 append({
0228                     label: 2050, // this value will be overwritten, but it set the type of the property to int
0229                     yearNumber: 2050,
0230                     isCurrent: (i > 0 && i < 11) // first and last year are outside the decade
0231                 })
0232             }
0233             updateDecadeOverview()
0234         }
0235     }
0236 
0237     /* ------------------------------------------------------- UI Starts From Here ----------------------------------------------------- */
0238 
0239     MonthViewHeader {
0240         id: viewHeader
0241 
0242         width: parent.width
0243         anchors.top: parent.top
0244         swipeView: swipeView
0245         monthViewRoot: root
0246     }
0247 
0248     PlasmaComponents3.SwipeView {
0249         id: swipeView
0250         anchors {
0251             top: viewHeader.bottom
0252             left: parent.left
0253             right: parent.right
0254             bottom: parent.bottom
0255         }
0256 
0257         activeFocusOnTab: false
0258         clip: true
0259 
0260         KeyNavigation.left: root.showDigitalClockHeader ? root.KeyNavigation.left : viewHeader.tabBar
0261         KeyNavigation.tab: viewHeader.tabButton
0262         Keys.onLeftPressed: event => { Keys.upPressed(event) }
0263         Keys.onUpPressed: viewHeader.tabBar.currentItem.forceActiveFocus(Qt.BacktabFocusReason);
0264 
0265         onCurrentIndexChanged: if (currentIndex > 1) {
0266             updateDecadeOverview();
0267         }
0268 
0269         WheelHandler {
0270             acceptedDevices: PointerDevice.Mouse
0271             orientation: Qt.Vertical
0272             parent: swipeView.currentItem
0273             onWheel: wheel => {
0274                 // magic number 15 for common "one scroll"
0275                 // See https://doc.qt.io/qt-6/qml-qtquick-wheelhandler.html#rotation-prop
0276                 while(rotation >= 15) {
0277                     rotation -= 15;
0278                     root.previousView();
0279                 }
0280                 while(rotation <= -15) {
0281                     rotation += 15;
0282                     root.nextView();
0283                 }
0284             }
0285         }
0286 
0287         // MonthView
0288         InfiniteList {
0289            id: mainDaysCalendar
0290 
0291            function handleUpPress(event) {
0292                 if(root.showDigitalClockHeader) {
0293                     root.Keys.upPressed(event);
0294                     return;
0295                 }
0296                 swipeView.Keys.upPressed(event);
0297             }
0298 
0299            backend: calendarBackend
0300            viewType: InfiniteList.ViewType.DayView
0301 
0302            delegate: DaysCalendar {
0303                 columns: calendarBackend.days
0304                 rows: calendarBackend.weeks
0305                 width: mainDaysCalendar.width
0306                 height: mainDaysCalendar.height
0307                 showWeekNumbers: root.showWeekNumbers
0308 
0309                 headerModel: calendarBackend.days
0310                 gridModel: switch (index) {
0311                 case 1:
0312                     return calendarBackend.daysModel;
0313                 case 0:
0314                     return mainDaysCalendar.previousModel;
0315                 case 2:
0316                     return mainDaysCalendar.nextModel;
0317                 }
0318 
0319                 dateMatchingPrecision: Calendar.MatchYearMonthAndDay
0320 
0321                 KeyNavigation.left: swipeView.KeyNavigation.left
0322                 KeyNavigation.tab: swipeView.KeyNavigation.tab
0323                 Keys.onUpPressed: event => { mainDaysCalendar.handleUpPress(event) }
0324 
0325                 onActivated: (index, date, item) => {
0326                     const rowNumber = Math.floor(index / columns);
0327                     week = 1 + calendarBackend.weeksModel[rowNumber];
0328                     root.currentDate = new Date(date.yearNumber, date.monthNumber - 1, date.dayNumber)
0329 
0330                     if (date.subLabel) {
0331                         root.currentDateAuxilliaryText = date.subLabel;
0332                     }
0333                 }
0334             }
0335         }
0336 
0337         // YearView
0338         InfiniteList {
0339            id: yearView
0340 
0341            backend: calendarBackend
0342            viewType: InfiniteList.ViewType.YearView
0343            delegate: DaysCalendar {
0344                 columns: 3
0345                 rows: 4
0346 
0347                 dateMatchingPrecision: Calendar.MatchYearAndMonth
0348                 width: yearView.width
0349                 height: yearView.height
0350                 gridModel: monthModel
0351 
0352                 KeyNavigation.left: swipeView.KeyNavigation.left
0353                 KeyNavigation.tab: swipeView.KeyNavigation.tab
0354                 Keys.onUpPressed: event => { mainDaysCalendar.handleUpPress(event) }
0355 
0356                 onActivated: (index, date, item) => {
0357                     calendarBackend.goToMonth(date.monthNumber);
0358                     swipeView.currentIndex = 0;
0359                 }
0360             }
0361         }
0362 
0363         // DecadeView
0364         InfiniteList {
0365             id: decadeView
0366 
0367             backend: calendarBackend
0368             viewType: InfiniteList.ViewType.DecadeView
0369             delegate: DaysCalendar {
0370                 readonly property int decade: {
0371                     const year = calendarBackend.displayedDate.getFullYear()
0372                     return year - year % 10
0373                 }
0374 
0375                 columns: 3
0376                 rows: 4
0377                 width: decadeView.width
0378                 height: decadeView.height
0379                 dateMatchingPrecision: Calendar.MatchYear
0380 
0381                 gridModel: switch (index) {
0382                 case 1:
0383                     return yearModel;
0384                 case 0:
0385                     return decadeView.previousModel;
0386                 case 2:
0387                     return decadeView.nextModel;
0388                 }
0389 
0390                 KeyNavigation.left: swipeView.KeyNavigation.left
0391                 KeyNavigation.tab: swipeView.KeyNavigation.tab
0392                 Keys.onUpPressed: event => { mainDaysCalendar.handleUpPress(event) }
0393 
0394                 onActivated: (index, date, item) => {
0395                     calendarBackend.goToYear(date.yearNumber);
0396                     swipeView.currentIndex = 1;
0397                 }
0398 
0399             }
0400         }
0401     }
0402 
0403     Component.onCompleted: {
0404         root.currentDate = calendarBackend.today
0405     }
0406 }