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 }