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 }