aerothemeplasma/Plasma/Plasma Widgets/User/Date and Time/org.kde.plasma.digitalclocklite/contents/ui/CalendarView.qml

452 lines
17 KiB
QML

/*
* Copyright 2013 Sebastian Kügler <sebas@kde.org>
* Copyright 2015 Martin Klapetek <mklapetek@kde.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.4
import QtQuick.Layouts 1.1
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.calendar 2.0 as PlasmaCalendar
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
PlasmaCore.Dialog {
id: calendar
objectName: "popupWindow"
flags: Qt.WindowStaysOnTopHint
location: PlasmaCore.Types.Floating
hideOnWindowDeactivate: !plasmoid.configuration.pin
//visible: isExpanded
PlasmaCore.FrameSvgItem {
id : panelSvg
visible: false
imagePath: "widgets/panel-background"
}
onVisibleChanged: {
var pos = popupPosition(width, height);
x = pos.x;
y = pos.y;
holidaysList.model = null;
holidaysList.model = monthView.daysModel.eventsForDate(monthView.currentDate);
}
onHeightChanged: {
var pos = popupPosition(width, height);
x = pos.x;
y = pos.y;
}
onWidthChanged: {
var pos = popupPosition(width, height);
x = pos.x;
y = pos.y;
}
function popupPosition(i, j) {
//w = _minimumWidth;
//height = _minimumHeight * 1.5;
//console.log(width + ", " + height);
var screenAvail = plasmoid.availableScreenRect;
var screen/*Geom*/ = plasmoid.screenGeometry;
//QtBug - QTBUG-64115
/*var screen = Qt.rect(screenAvail.x + screenGeom.x,
screenAvail.y + screenGeom.y,
screenAvail.width,
screenAvail.height);*/
var offset = PlasmaCore.Units.smallSpacing;
// Fall back to bottom-left of screen area when the applet is on the desktop or floating.
var x = offset;
var y = screen.height - j - offset;
var horizMidPoint = screen.x + (screen.width / 2);
var vertMidPoint = screen.y + (screen.height / 2);
var appletTopLeft = parent.mapToGlobal(0, 0);
var appletBottomLeft = parent.mapToGlobal(0, parent.height);
x = (appletTopLeft.x < horizMidPoint) ? screen.x : (screen.x + screen.width) - i;
if (appletTopLeft.x < horizMidPoint) {
x += offset
} else if (appletTopLeft.x + i > horizMidPoint){
x -= offset
}
if (plasmoid.location == PlasmaCore.Types.TopEdge) {
/*this is floatingAvatar.width*/
offset = PlasmaCore.Units.smallSpacing*2;
y = screen.y + parent.height + panelSvg.margins.bottom + offset;
} else {
offset = PlasmaCore.Units.smallSpacing*2;
y = screen.y + screen.height - (parent.height) - j - panelSvg.margins.top - offset;
}
//console.log(appletTopLeft + ", " + appletBottomLeft);
return Qt.point(x, y);
}
//Layout.minimumWidth: _minimumWidth
//Layout.minimumHeight: _minimumHeight
//x: 0
//y: 0
// The "sensible" values
property int _minimumWidth: (showAgenda ? agendaViewWidth : 0) + monthViewWidth
property int _minimumHeight: PlasmaCore.Units.gridUnit * 12
//Layout.preferredWidth: _minimumWidth
//Layout.preferredHeight: _minimumHeight * 1.5
readonly property bool showAgenda: PlasmaCalendar.EventPluginsManager.enabledPlugins.length > 0
readonly property int agendaViewWidth: _minimumHeight
readonly property int monthViewWidth: monthView.showWeekNumbers ? Math.round(_minimumHeight * 1.25) : Math.round(_minimumHeight * 1.125)
property int boxWidth: (agendaViewWidth + monthViewWidth - ((showAgenda ? 3 : 4) * spacing)) / 2
property int spacing: units.largeSpacing
property alias borderWidth: monthView.borderWidth
property alias monthView: monthView
property bool debug: false
property bool isExpanded: plasmoid.expanded
onIsExpandedChanged: {
// clear all the selections when the plasmoid is showing/hiding
monthView.resetToToday();
}
FocusScope {
Layout.minimumWidth: _minimumWidth * 0.8
Layout.minimumHeight: _minimumHeight * 1.2
Layout.maximumWidth: _minimumWidth * 0.8
Layout.maximumHeight: _minimumHeight * 1.2
Layout.preferredWidth: _minimumWidth * 0.8
Layout.preferredHeight: _minimumHeight * 1.2
PlasmaExtras.Heading {
id: longDateLabel
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.topMargin: PlasmaCore.Units.smallSpacing*2
//height: dayHeading.height + dateHeading.height
width: paintedWidth
horizontalAlignment: Text.AlignHCenter
//font.pixelSize: height
//font.weight: Font.Light
text: agenda.dateString("dddd") + ", " + Qt.locale().standaloneMonthName(monthView.currentDate.getMonth()) + agenda.dateString(" dd") + ", " + agenda.dateString("yyyy")
level: 5
}
Item {
id: agenda
visible: calendar.showAgenda
width: boxWidth * 0.75
anchors {
top: parent.top
right: parent.right
bottom: parent.bottom
//rightMargin: units.smallSpacing
topMargin: spacing
bottomMargin: spacing
}
function dateString(format) {
return Qt.formatDate(monthView.currentDate, format);
}
function formatDateWithoutYear(date) {
// Unfortunatelly Qt overrides ECMA's Date.toLocaleDateString(),
// which is able to return locale-specific date-and-month-only date
// formats, with its dumb version that only supports Qt::DateFormat
// enum subset. So to get a day-and-month-only date format string we
// must resort to this magic and hope there are no locales that use
// other separators...
var format = Qt.locale().dateFormat(Locale.ShortFormat).replace(/[./ ]*Y{2,4}[./ ]*/i, '');
return Qt.formatDate(date, format);
}
Connections {
target: monthView
onCurrentDateChanged: {
// Apparently this is needed because this is a simple QList being
// returned and if the list for the current day has 1 event and the
// user clicks some other date which also has 1 event, QML sees the
// sizes match and does not update the labels with the content.
// Resetting the model to null first clears it and then correct data
// are displayed.
holidaysList.model = null;
holidaysList.model = monthView.daysModel.eventsForDate(monthView.currentDate);
}
}
Connections {
target: monthView.daysModel
onAgendaUpdated: {
// Checks if the dates are the same, comparing the date objects
// directly won't work and this does a simple integer subtracting
// so should be fastest. One of the JS weirdness.
if (updatedDate - monthView.currentDate === 0) {
holidaysList.model = null;
holidaysList.model = monthView.daysModel.eventsForDate(monthView.currentDate);
}
}
}
Connections {
target: plasmoid.configuration
onEnabledCalendarPluginsChanged: {
PlasmaCalendar.EventPluginsManager.enabledPlugins = plasmoid.configuration.enabledCalendarPlugins;
}
}
Binding {
target: plasmoid
property: "hideOnWindowDeactivate"
value: !plasmoid.configuration.pin
}
TextMetrics {
id: dateLabelMetrics
// Date/time are arbitrary values with all parts being two-digit
readonly property string timeString: Qt.formatTime(new Date(2000, 12, 12, 12, 12, 12, 12))
readonly property string dateString: agenda.formatDateWithoutYear(new Date(2000, 12, 12, 12, 12, 12))
font: theme.defaultFont
text: timeString.length > dateString.length ? timeString : dateString
}
PlasmaExtras.ScrollArea {
id: holidaysView
anchors {
top: parent.top
topMargin: PlasmaCore.Units.largeSpacing
left: parent.left
right: parent.right
bottom: parent.bottom
}
flickableItem.boundsBehavior: Flickable.StopAtBounds
ListView {
id: holidaysList
delegate: PlasmaComponents.ListItem {
id: eventItem
property bool hasTime: {
// Explicitly all-day event
if (modelData.isAllDay) {
return false;
}
// Multi-day event which does not start or end today (so
// is all-day from today's point of view)
if (modelData.startDateTime - monthView.currentDate < 0 &&
modelData.endDateTime - monthView.currentDate > 86400000) { // 24hrs in ms
return false;
}
// Non-explicit all-day event
var startIsMidnight = modelData.startDateTime.getHours() == 0
&& modelData.startDateTime.getMinutes() == 0;
var endIsMidnight = modelData.endDateTime.getHours() == 0
&& modelData.endDateTime.getMinutes() == 0;
var sameDay = modelData.startDateTime.getDate() == modelData.endDateTime.getDate()
&& modelData.startDateTime.getDay() == modelData.endDateTime.getDay()
if (startIsMidnight && endIsMidnight && sameDay) {
return false
}
return true;
}
PlasmaCore.ToolTipArea {
width: parent.width
height: eventGrid.height
active: eventTitle.truncated || eventDescription.truncated
mainText: active ? eventTitle.text : ""
subText: active ? eventDescription.text : ""
GridLayout {
id: eventGrid
columns: 3
rows: 2
rowSpacing: 0
columnSpacing: 2 * units.smallSpacing
width: parent.width
Rectangle {
id: eventColor
Layout.row: 0
Layout.column: 0
Layout.rowSpan: 2
Layout.fillHeight: true
color: modelData.eventColor
width: 5 * units.devicePixelRatio
visible: modelData.eventColor !== ""
}
PlasmaComponents.Label {
id: startTimeLabel
readonly property bool startsToday: modelData.startDateTime - monthView.currentDate >= 0
readonly property bool startedYesterdayLessThan12HoursAgo: modelData.startDateTime - monthView.currentDate >= -43200000 //12hrs in ms
Layout.row: 0
Layout.column: 1
Layout.minimumWidth: dateLabelMetrics.width
text: startsToday || startedYesterdayLessThan12HoursAgo
? Qt.formatTime(modelData.startDateTime)
: agenda.formatDateWithoutYear(modelData.startDateTime)
horizontalAlignment: Qt.AlignRight
visible: eventItem.hasTime
}
PlasmaComponents.Label {
id: endTimeLabel
readonly property bool endsToday: modelData.endDateTime - monthView.currentDate <= 86400000 // 24hrs in ms
readonly property bool endsTomorrowInLessThan12Hours: modelData.endDateTime - monthView.currentDate <= 86400000 + 43200000 // 36hrs in ms
Layout.row: 1
Layout.column: 1
Layout.minimumWidth: dateLabelMetrics.width
text: endsToday || endsTomorrowInLessThan12Hours
? Qt.formatTime(modelData.endDateTime)
: agenda.formatDateWithoutYear(modelData.endDateTime)
horizontalAlignment: Qt.AlignRight
enabled: false
visible: eventItem.hasTime
}
PlasmaComponents.Label {
id: eventTitle
readonly property bool wrap: eventDescription.text === ""
Layout.row: 0
Layout.rowSpan: wrap ? 2 : 1
Layout.column: 2
Layout.fillWidth: true
elide: Text.ElideRight
text: modelData.title
verticalAlignment: Text.AlignVCenter
maximumLineCount: 2
wrapMode: wrap ? Text.Wrap : Text.NoWrap
}
PlasmaComponents.Label {
id: eventDescription
Layout.row: 1
Layout.column: 2
Layout.fillWidth: true
elide: Text.ElideRight
text: modelData.description
verticalAlignment: Text.AlignVCenter
enabled: false
visible: text !== ""
}
}
}
}
section.property: "modelData.eventType"
section.delegate: PlasmaExtras.Heading {
level: 5
elide: Text.ElideRight
text: section
font.weight: Font.Bold
}
}
}
PlasmaExtras.Heading {
anchors.fill: holidaysView
//anchors.leftMargin: units.smallSpacing
anchors.rightMargin: units.largeSpacing
text: monthView.isToday(monthView.currentDate) ? i18n("No events for today") + "\n"
: i18n("No events for this day") + "\n";
level: 5
opacity: 0.8
visible: holidaysList.count == 0
}
}
Item {
id: cal
width: boxWidth
anchors {
top: parent.top
left: parent.left
bottom: parent.bottom
leftMargin: PlasmaCore.Units.smallSpacing * 2
topMargin: PlasmaCore.Units.largeSpacing * 2
rightMargin: spacing
bottomMargin: 0
}
CustomMonthView {
id: monthView
//borderOpacity: 0.25
today: root.tzDate
showWeekNumbers: plasmoid.configuration.showWeekNumbers
firstDayOfWeek: Locale.Monday
//showCustomHeader: true
anchors.fill: parent
//anchors.margins: 0
}
}
// Allows the user to keep the calendar open for reference
/*PlasmaComponents.ToolButton {
anchors.right: parent.right
width: Math.round(units.gridUnit * 1.25)
height: width
checkable: true
iconSource: "window-pin"
checked: plasmoid.configuration.pin
onCheckedChanged: plasmoid.configuration.pin = checked
}*/
}
Component.onCompleted: {
calendar.backgroundHints = 2;
var pos = popupPosition(width, height);
x = pos.x;
y = pos.y;
}
}