Commit d0d2c306 authored by Glen Ditchfield's avatar Glen Ditchfield 🐛 Committed by Allen Winter
Browse files

Improve tool tips for to-dos

There are several problems with tool tips for recurring multi-day to-dos:
 * The due date is wrong.
 * The start date is just a date, without a time.
 * The to-do is displayed in the agenda view on the start date.
 * The agenda view passes the start date down to `dateRangeText()`, which
   expects the due date.
 * `dateRangeText()` calls `getNextDateTime()` expecting a due date, but
   `getNextDateTime()` returns start dates.

This patch adjusts `dateRangeText()` to accept any date between the to-do's
start and end dates, adjusts the tool tip contents, and incidentally fixes
BUG: 360730
parent 0e01a886
Pipeline #23188 passed with stage
in 5 minutes and 29 seconds
......@@ -10,7 +10,7 @@ configure_file(test_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/test_config.h @ON
include_directories(${CMAKE_SOURCE_DIR}/src ${CMAKE_BINARY_DIR}/src)
ecm_add_tests(testdndfactory.cpp teststringify.cpp
ecm_add_tests(testdndfactory.cpp teststringify.cpp testtodotooltip.cpp
NAME_PREFIX "kcalutils-"
LINK_LIBRARIES KF5CalendarUtils KF5::I18n Qt5::Test
)
......@@ -24,3 +24,4 @@ ecm_add_test(testincidenceformatter.cpp
# Make sure that dates are formatted in C locale
set_tests_properties(kcalutils-testincidenceformatter PROPERTIES ENVIRONMENT "LC_ALL=C")
set_tests_properties(kcalutils-testtodotooltip PROPERTIES ENVIRONMENT "LC_ALL=C")
/*
Copyright (c) 2020 Glen Ditchfield <GJDitchfield@acm.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "testtodotooltip.h"
#include <KCalendarCore/Todo>
#include "incidenceformatter.h"
#include <QRegularExpression>
#include <QTest>
// Standard values for to-dos.
static const bool ALL_DAY = true;
static const bool RECURS = true;
static const QDateTime START_DT { QDate(2020, 6, 10), QTime(11, 0, 0) };
static const QDateTime DUE_DT { QDate(2020, 6, 12), QTime(11, 30, 0) };
static const QDate AS_OF_DATE { 2020, 6, 12 };
static const QString SUMMARY { QStringLiteral("Do something") };
static const QString CAL_NAME { QStringLiteral("A calendar") };
// Field names in tool tips.
static const QString CALENDAR { QStringLiteral("Calendar") };
static const QString START { QStringLiteral("Start") };
static const QString DUE { QStringLiteral("Due") };
static const QString PERCENT { QStringLiteral("Percent Done") };
static const QString COMPLETED { QStringLiteral("Completed") };
static const QString DURATION { QStringLiteral("Duration") };
static const QString RECURRENCE { QStringLiteral("Recurrence") };
static const QString PRIORITY { QStringLiteral("Priority") };
// Common expected field values in tool tips.
static const QString EXPECTED_RECURRENCE { QStringLiteral("Recurs every 7 days until") };
static const QString EXPECTED_DURATION_DAYS { QStringLiteral("3 days") };
static const QString EXPECTED_DURATION_DT { QStringLiteral("2 days 30 minutes") };
static const QString EXPECTED_PCT100 { QStringLiteral("100%") };
static const QString EXPECTED_PCT50 { QStringLiteral("50%") };
static const QString EXPECTED_PCT0 { QStringLiteral("0%") };
using namespace KCalUtils::IncidenceFormatter;
// Create a to-do that may or may not be an all-day to-do, may or may nor recur,
// and with the given start and due dates (which may be invalid).
// Other to-do fields are fixed.
static KCalendarCore::Todo::Ptr makeToDo(bool allday, bool recurs, QDateTime dtStart, QDateTime dtDue)
{
KCalendarCore::Todo::Ptr todo {new KCalendarCore::Todo };
todo->setSummary(SUMMARY);
todo->setDtStart(dtStart);
todo->setDtDue(dtDue);
todo->setAllDay(allday);
if (recurs) {
todo->recurrence()->setDaily(7);
todo->recurrence()->setDuration(3);
todo->setCompleted(dtStart);
}
todo->setPercentComplete(50);
return todo;
}
// Convert a tool tip to a convenient form for testing.
static QString plain(QString s)
{
return s.replace(QStringLiteral("&nbsp;"), QStringLiteral(" "))
.replace(QStringLiteral("<hr>"), QStringLiteral("\n---\n"))
.replace(QStringLiteral("<br>"), QStringLiteral("\n"))
.remove(QRegularExpression(QStringLiteral("<[/a-z]+>")))
;
}
// Return a regular expression that matches a field name and value.
static QRegularExpression field(const QString &name, const QString &value)
{
return QRegularExpression(QStringLiteral("\\b%1:\\s*%2").arg(name, value));
}
// Return a regular expression that matches just a field name.
static QRegularExpression field(const QString &name) {
return QRegularExpression(QStringLiteral("\\b%1:").arg(name));
}
void TestTodoToolTip::testNonrecurring_data()
{
QTest::addColumn<bool>("allDay");
QTest::addColumn<QDateTime>("dtStart");
QTest::addColumn<QDateTime>("dtDue");
QTest::addColumn<QDate>("asOfDate");
// Tests for the agenda and month views.
QTest::newRow("all day,both") << ALL_DAY << START_DT << DUE_DT << AS_OF_DATE;
QTest::newRow("all day,start") << ALL_DAY << START_DT << QDateTime() << AS_OF_DATE;
QTest::newRow("all day,due") << ALL_DAY << QDateTime() << DUE_DT << AS_OF_DATE;
QTest::newRow("all day,neither") << ALL_DAY << QDateTime() << QDateTime() << AS_OF_DATE;
QTest::newRow("timed,both") << !ALL_DAY << START_DT << DUE_DT << AS_OF_DATE;
QTest::newRow("timed,start") << !ALL_DAY << START_DT << QDateTime() << AS_OF_DATE;
QTest::newRow("timed,due") << !ALL_DAY << QDateTime() << DUE_DT << AS_OF_DATE;
QTest::newRow("timed,neither") << !ALL_DAY << QDateTime() << QDateTime() << AS_OF_DATE;
// Tests for the to-do list view.
QTest::newRow("all day,both,dateless") << ALL_DAY << START_DT << DUE_DT << QDate();
QTest::newRow("all day,start,dateless") << ALL_DAY << START_DT << QDateTime() << QDate();
QTest::newRow("all day,due,dateless") << ALL_DAY << QDateTime() << DUE_DT << QDate();
QTest::newRow("all day,neither,dateless") << ALL_DAY << QDateTime() << QDateTime() << QDate();
QTest::newRow("timed,both,dateless") << !ALL_DAY << START_DT << DUE_DT << QDate();
QTest::newRow("timed,start,dateless") << !ALL_DAY << START_DT << QDateTime() << QDate();
QTest::newRow("timed,due,dateless") << !ALL_DAY << QDateTime() << DUE_DT << QDate();
QTest::newRow("timed,neither,dateless") << !ALL_DAY << QDateTime() << QDateTime() << QDate();
}
// Test for the values of tool tip fields, or their absence, in non-recurring to-dos.
void TestTodoToolTip::testNonrecurring()
{
QFETCH(bool, allDay);
QFETCH(QDateTime, dtStart);
QFETCH(QDateTime, dtDue);
QFETCH(QDate, asOfDate);
auto todo = makeToDo(allDay, !RECURS, dtStart, dtDue);
auto toolTip = plain(toolTipStr(CAL_NAME, todo, asOfDate, false));
QVERIFY(toolTip.contains(QRegularExpression(SUMMARY)));
QVERIFY(toolTip.contains(field(CALENDAR, CAL_NAME)));
QVERIFY(toolTip.contains(field(PERCENT, EXPECTED_PCT50 )));
QVERIFY(!toolTip.contains(field(COMPLETED)));
QVERIFY(!toolTip.contains(field(RECURRENCE)));
if (dtStart.isValid()) {
QVERIFY(toolTip.contains(field(START, dateTimeToString(dtStart, allDay, false))));
} else {
QVERIFY(!toolTip.contains(field(START)));
}
if (dtDue.isValid()) {
QVERIFY(toolTip.contains(field(DUE, dateTimeToString(dtDue, allDay, false))));
} else {
QVERIFY(!toolTip.contains(field(DUE)));
}
if (dtStart.isValid() && dtDue.isValid()) {
if (allDay) {
QVERIFY(toolTip.contains(field(DURATION, EXPECTED_DURATION_DAYS)));
} else {
QVERIFY(toolTip.contains(field(DURATION, EXPECTED_DURATION_DT)));
}
} else {
QVERIFY(!toolTip.contains(field(DURATION)));
}
}
// Tool tips for all-day non-recurring to-dos should contain a completion percentage
// if they are incomplete, or a completion date otherwise.
void TestTodoToolTip::testAlldayNonrecurringDone()
{
auto todo = makeToDo(ALL_DAY, !RECURS, START_DT, DUE_DT);
todo->setCompleted(START_DT);
auto toolTip = plain(toolTipStr(CAL_NAME, todo, AS_OF_DATE, false));
QVERIFY(toolTip.contains(field(COMPLETED, dateTimeToString(START_DT, ALL_DAY, false))));
QVERIFY(!toolTip.contains(field(PERCENT)));
toolTip = plain(toolTipStr(CAL_NAME, todo, QDate(), false));
QVERIFY(toolTip.contains(field(COMPLETED, dateTimeToString(START_DT, ALL_DAY, false))));
QVERIFY(!toolTip.contains(field(PERCENT)));
}
// Tool tips for non-all-day non-recurring to-dos should contain a completion percentage
// if they are incomplete, or a completion date otherwise.
void TestTodoToolTip::testTimedNonrecurringDone()
{
auto todo = makeToDo(!ALL_DAY, !RECURS, START_DT, DUE_DT);
todo->setCompleted(START_DT);
auto toolTip = plain(toolTipStr(CAL_NAME, todo, AS_OF_DATE, false));
QVERIFY(toolTip.contains(field(COMPLETED, dateTimeToString(START_DT, !ALL_DAY, false))));
QVERIFY(!toolTip.contains(field(PERCENT)));
toolTip = plain(toolTipStr(CAL_NAME, todo, QDate(), false));
QVERIFY(toolTip.contains(field(COMPLETED, dateTimeToString(START_DT, !ALL_DAY, false))));
QVERIFY(!toolTip.contains(field(PERCENT)));
}
void TestTodoToolTip::testRecurringOnDate_data()
{
QTest::addColumn<bool>("allDay");
QTest::addColumn<QDateTime>("dtStart");
QTest::addColumn<QDateTime>("dtDue");
QTest::addColumn<QDate>("asOfDate");
QTest::addColumn<QString>("pct");
QTest::addColumn<int>("daysOffset");
QTest::addColumn<QString>("dur");
// Test the tool tip for each day of each occurrence of all-day to-dos.
QTest::newRow("All day, 1st, day 1") << ALL_DAY << START_DT << DUE_DT
<< START_DT.date() << EXPECTED_PCT100 << 0 << EXPECTED_DURATION_DAYS;
QTest::newRow("All day, 1st, day 2") << ALL_DAY << START_DT << DUE_DT
<< START_DT.date().addDays(1) << EXPECTED_PCT100 << 0 << EXPECTED_DURATION_DAYS;
QTest::newRow("All day, 1st, day 3") << ALL_DAY << START_DT << DUE_DT
<< DUE_DT.date() << EXPECTED_PCT100 << 0 << EXPECTED_DURATION_DAYS;
QTest::newRow("All day, 1st, only day") << ALL_DAY << DUE_DT << DUE_DT
<< DUE_DT.date() << EXPECTED_PCT100 << 0 << QStringLiteral("1 day");
QTest::newRow("All day, 2nd, day 1") << ALL_DAY << START_DT << DUE_DT
<< START_DT.date().addDays(7) << EXPECTED_PCT50 << 7 << EXPECTED_DURATION_DAYS;
QTest::newRow("All day, 2nd, day 2") << ALL_DAY << START_DT << DUE_DT
<< START_DT.date().addDays(8) << EXPECTED_PCT50 << 7 << EXPECTED_DURATION_DAYS;
QTest::newRow("All day, 2nd, day 3") << ALL_DAY << START_DT << DUE_DT
<< DUE_DT.date().addDays(7) << EXPECTED_PCT50 << 7 << EXPECTED_DURATION_DAYS;
QTest::newRow("All day, 2nd, only day") << ALL_DAY << DUE_DT << DUE_DT
<< DUE_DT.date().addDays(7) << EXPECTED_PCT50 << 7 << QStringLiteral("1 day");
QTest::newRow("All day, 3rd, day 1") << ALL_DAY << START_DT << DUE_DT
<< START_DT.date().addDays(14) << EXPECTED_PCT0 << 14 << EXPECTED_DURATION_DAYS;
QTest::newRow("All day, 3rd, day 2") << ALL_DAY << START_DT << DUE_DT
<< START_DT.date().addDays(15) << EXPECTED_PCT0 << 14 << EXPECTED_DURATION_DAYS;
QTest::newRow("All day, 3rd, day 3") << ALL_DAY << START_DT << DUE_DT
<< DUE_DT.date().addDays(14) << EXPECTED_PCT0 << 14 << EXPECTED_DURATION_DAYS;
QTest::newRow("All day, 3rd, only day") << ALL_DAY << DUE_DT << DUE_DT
<< DUE_DT.date().addDays(14) << EXPECTED_PCT0 << 14 << QStringLiteral("1 day");
// Test the tool tip for each day of each occurrence of time-of-day to-dos.
QTest::newRow("Timed, 1st, day 1") << !ALL_DAY << START_DT << DUE_DT
<< START_DT.date() << EXPECTED_PCT100 << 0 << EXPECTED_DURATION_DT;
QTest::newRow("Timed, 1st, day 2") << !ALL_DAY << START_DT << DUE_DT
<< START_DT.date().addDays(1) << EXPECTED_PCT100 << 0 << EXPECTED_DURATION_DT;
QTest::newRow("Timed, 1st, day 3") << !ALL_DAY << START_DT << DUE_DT
<< DUE_DT.date() << EXPECTED_PCT100 << 0 << EXPECTED_DURATION_DT;
QTest::newRow("Timed, 1st, only day") << !ALL_DAY << START_DT.addDays(2) << DUE_DT
<< DUE_DT.date() << EXPECTED_PCT100 << 0 << QStringLiteral("30 minutes");
QTest::newRow("Timed, 2nd, day 1") << !ALL_DAY << START_DT << DUE_DT
<< START_DT.date().addDays(7) << EXPECTED_PCT50 << 7 << EXPECTED_DURATION_DT;
QTest::newRow("Timed, 2nd, day 2") << !ALL_DAY << START_DT << DUE_DT
<< START_DT.date().addDays(8) << EXPECTED_PCT50 << 7 << EXPECTED_DURATION_DT;
QTest::newRow("Timed, 2nd, day 3") << !ALL_DAY << START_DT << DUE_DT
<< DUE_DT.date().addDays(7) << EXPECTED_PCT50 << 7 << EXPECTED_DURATION_DT;
QTest::newRow("Timed, All 2nd, only day") << !ALL_DAY << START_DT.addDays(2) << DUE_DT
<< DUE_DT.date().addDays(7) << EXPECTED_PCT50 << 7 << QStringLiteral("30 minutes");
QTest::newRow("Timed, 3rd, day 1") << !ALL_DAY << START_DT << DUE_DT
<< START_DT.date().addDays(14) << EXPECTED_PCT0 << 14 << EXPECTED_DURATION_DT;
QTest::newRow("Timed, 3rd, day 2") << !ALL_DAY << START_DT << DUE_DT
<< START_DT.date().addDays(15) << EXPECTED_PCT0 << 14 << EXPECTED_DURATION_DT;
QTest::newRow("Timed, 3rd, day 3") << !ALL_DAY << START_DT << DUE_DT
<< DUE_DT.date().addDays(14) << EXPECTED_PCT0 << 14 << EXPECTED_DURATION_DT;
QTest::newRow("Timed, 3rd, only day") << !ALL_DAY << START_DT.addDays(2) << DUE_DT
<< DUE_DT.date().addDays(14) << EXPECTED_PCT0 << 14 << QStringLiteral("30 minutes");
}
// Test for the values of tool tip fields, or their absence, for specific dates
// in occurrences of recurring to-dos.
void TestTodoToolTip::testRecurringOnDate()
{
QFETCH(bool, allDay);
QFETCH(QDateTime, dtStart);
QFETCH(QDateTime, dtDue);
QFETCH(QDate, asOfDate);
QFETCH(QString, pct);
QFETCH(int, daysOffset);
QFETCH(QString, dur);
auto todo = makeToDo(allDay, RECURS, dtStart, dtDue);
auto toolTip = plain(toolTipStr(CAL_NAME, todo, asOfDate, false));
QVERIFY(toolTip.contains(QRegularExpression(SUMMARY)));
QVERIFY(toolTip.contains(field(CALENDAR, CAL_NAME)));
QVERIFY(toolTip.contains(field(PERCENT, pct)));
QVERIFY(!toolTip.contains(field(COMPLETED)));
QVERIFY(toolTip.contains(field(START, dateTimeToString(dtStart.addDays(daysOffset), allDay, false))));
QVERIFY(toolTip.contains(field(DUE, dateTimeToString(dtDue.addDays(daysOffset), allDay, false))));
QVERIFY(toolTip.contains(field(DURATION, dur)));
QVERIFY(toolTip.contains(field(RECURRENCE, EXPECTED_RECURRENCE)));
}
// Tool tips for no particular date show the properties of the first uncompleted occurrence.
void TestTodoToolTip::testAlldayRecurringNoDate()
{
auto todo = makeToDo(ALL_DAY, RECURS, START_DT, DUE_DT);
auto toolTip = plain(toolTipStr(CAL_NAME, todo, QDate(), false));
QVERIFY(toolTip.contains(QRegularExpression(SUMMARY)));
QVERIFY(toolTip.contains(field(CALENDAR, CAL_NAME)));
QVERIFY(toolTip.contains(field(PERCENT, EXPECTED_PCT50 )));
QVERIFY(!toolTip.contains(field(COMPLETED)));
QVERIFY(toolTip.contains(field(START, dateTimeToString(START_DT.addDays(7), ALL_DAY, false))));
QVERIFY(toolTip.contains(field(DUE, dateTimeToString(DUE_DT.addDays(7), ALL_DAY, false))));
QVERIFY(toolTip.contains(field(DURATION, EXPECTED_DURATION_DAYS)));
QVERIFY(toolTip.contains(field(RECURRENCE, EXPECTED_RECURRENCE)));
}
// Tool tips for no particular date show the properties of the first uncompleted occurrence.
void TestTodoToolTip::testTimedRecurringNoDate()
{
auto todo = makeToDo(!ALL_DAY, RECURS, START_DT, DUE_DT);
auto toolTip = plain(toolTipStr(CAL_NAME, todo, QDate(), false));
QVERIFY(toolTip.contains(QRegularExpression(SUMMARY)));
QVERIFY(toolTip.contains(field(CALENDAR, CAL_NAME)));
QVERIFY(toolTip.contains(field(PERCENT, EXPECTED_PCT50 )));
QVERIFY(!toolTip.contains(field(COMPLETED)));
QVERIFY(toolTip.contains(field(START, dateTimeToString(START_DT.addDays(7), !ALL_DAY, false))));
QVERIFY(toolTip.contains(field(DUE, dateTimeToString(DUE_DT.addDays(7), !ALL_DAY, false))));
QVERIFY(toolTip.contains(field(DURATION, EXPECTED_DURATION_DT)));
QVERIFY(toolTip.contains(field(RECURRENCE, EXPECTED_RECURRENCE)));
}
// Tool tips for recurring to-dos with no due dates do not have "duration"
// or "due" fields.
void TestTodoToolTip::testAlldayRecurringNeverDue()
{
auto todo = makeToDo(ALL_DAY, RECURS, START_DT, QDateTime());
auto toolTip = plain(toolTipStr(CAL_NAME, todo, QDate(), false));
QVERIFY(toolTip.contains(QRegularExpression(SUMMARY)));
QVERIFY(toolTip.contains(field(CALENDAR, CAL_NAME)));
QVERIFY(toolTip.contains(field(PERCENT, EXPECTED_PCT50 )));
QVERIFY(!toolTip.contains(field(COMPLETED)));
QVERIFY(toolTip.contains(field(START, dateTimeToString(START_DT.addDays(7), ALL_DAY, false))));
QVERIFY(!toolTip.contains(field(DUE)));
QVERIFY(!toolTip.contains(field(DURATION)));
QVERIFY(toolTip.contains(field(RECURRENCE, EXPECTED_RECURRENCE)));
}
// Tool tips for recurring to-dos with no due dates do not have "duration"
// or "due" fields.
void TestTodoToolTip::testTimedRecurringNeverDue()
{
auto todo = makeToDo(!ALL_DAY, RECURS, START_DT, QDateTime());
auto toolTip = plain(toolTipStr(CAL_NAME, todo, QDate(), false));
QVERIFY(toolTip.contains(QRegularExpression(SUMMARY)));
QVERIFY(toolTip.contains(field(CALENDAR, CAL_NAME)));
QVERIFY(toolTip.contains(field(PERCENT, EXPECTED_PCT50 )));
QVERIFY(toolTip.contains(field(START, dateTimeToString(START_DT.addDays(7), !ALL_DAY, false))));
QVERIFY(!toolTip.contains(field(DUE)));
QVERIFY(!toolTip.contains(field(DURATION)));
QVERIFY(toolTip.contains(field(RECURRENCE, EXPECTED_RECURRENCE)));
}
// Tool tips for recurring to-dos should contain a "completed" field instead of
// a percentage field after the last occurrence has been marked as complete.
void TestTodoToolTip::testAlldayRecurringDone()
{
auto todo = makeToDo(ALL_DAY, RECURS, START_DT, DUE_DT);
todo->setCompleted(START_DT.addDays(14)); // Complete the second occurrence.
todo->setCompleted(START_DT.addMonths(1)); // Complete the third occurrence.
auto toolTip = plain(toolTipStr(CAL_NAME, todo, AS_OF_DATE, false));
QVERIFY(toolTip.contains(field(COMPLETED, dateTimeToString(START_DT.addMonths(1), ALL_DAY, false))));
QVERIFY(!toolTip.contains(field(PERCENT)));
toolTip = plain(toolTipStr(CAL_NAME, todo, QDate(), false));
QVERIFY(toolTip.contains(field(COMPLETED, dateTimeToString(START_DT.addMonths(1), ALL_DAY, false))));
QVERIFY(!toolTip.contains(field(PERCENT)));
}
// Tool tips for recurring to-dos should contain a "completed" field instead of
// a percentage field after the last occurrence has been marked as complete.
void TestTodoToolTip::testTimedRecurringDone()
{
auto todo = makeToDo(!ALL_DAY, RECURS, START_DT, DUE_DT);
todo->setCompleted(START_DT.addDays(14)); // Complete the second occurrence.
todo->setCompleted(START_DT.addMonths(1)); // Complete the third occurrence.
auto toolTip = plain(toolTipStr(CAL_NAME, todo, AS_OF_DATE, false));
QVERIFY(toolTip.contains(field(COMPLETED, dateTimeToString(START_DT.addMonths(1), !ALL_DAY, false))));
QVERIFY(!toolTip.contains(field(PERCENT)));
toolTip = plain(toolTipStr(CAL_NAME, todo, QDate(), false));
QVERIFY(toolTip.contains(field(COMPLETED, dateTimeToString(START_DT.addMonths(1), !ALL_DAY, false))));
QVERIFY(!toolTip.contains(field(PERCENT)));
}
// Tool tips should only contain a "priority" field if the priority is not zero.
void TestTodoToolTip::testPriority()
{
auto todo = makeToDo(!ALL_DAY, RECURS, START_DT, DUE_DT);
auto toolTip = plain(toolTipStr(CAL_NAME, todo, AS_OF_DATE, false));
QVERIFY(!toolTip.contains(field(PRIORITY)));
todo->setPriority(5);
toolTip = plain(toolTipStr(CAL_NAME, todo, AS_OF_DATE, false));
QVERIFY(toolTip.contains(field(PRIORITY, QStringLiteral("5"))));
}
QTEST_MAIN(TestTodoToolTip)
/*
Copyright (c) 2020 Glen Ditchfield <GJDitchfield@acm.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef TESTTODOTOOLTIP_H
#define TESTTODOTOOLTIP_H
#include <QObject>
class TestTodoToolTip : public QObject
{
Q_OBJECT
private Q_SLOTS:
void testNonrecurring_data();
void testNonrecurring();
void testAlldayNonrecurringDone();
void testTimedNonrecurringDone();
void testRecurringOnDate_data();
void testRecurringOnDate();
void testAlldayRecurringNoDate();
void testTimedRecurringNoDate();
void testAlldayRecurringNeverDue();
void testTimedRecurringNeverDue();
void testAlldayRecurringDone();
void testTimedRecurringDone();
void testPriority();
};
#endif
......@@ -2429,7 +2429,7 @@ protected:
bool visit(const FreeBusy::Ptr &fb) override;
QString dateRangeText(const Event::Ptr &event, QDate date);
QString dateRangeText(const Todo::Ptr &todo, QDate date);
QString dateRangeText(const Todo::Ptr &todo, QDate asOfDate);
QString dateRangeText(const Journal::Ptr &journal);
QString dateRangeText(const FreeBusy::Ptr &fb);
......@@ -2496,46 +2496,60 @@ QString IncidenceFormatter::ToolTipVisitor::dateRangeText(const Event::Ptr &even
return ret.replace(QLatin1Char(' '), QLatin1String("&nbsp;"));
}
QString IncidenceFormatter::ToolTipVisitor::dateRangeText(const Todo::Ptr &todo, QDate date)
QString IncidenceFormatter::ToolTipVisitor::dateRangeText(const Todo::Ptr &todo, QDate asOfDate)
{
//FIXME: support mRichText==false
QString ret;
if (todo->hasStartDate()) {
QDateTime startDt = todo->dtStart();
if (todo->recurs() && date.isValid()) {
startDt.setDate(date);
//FIXME: doesn't handle to-dos that occur more than once per day.
QDateTime startDt { todo->dtStart(false) };
QDateTime dueDt { todo->dtDue(false) };
if (todo->recurs() && asOfDate.isValid()) {
const QDateTime limit { asOfDate.addDays(1), QTime(0, 0, 0), Qt::LocalTime };
startDt = todo->recurrence()->getPreviousDateTime(limit);
if (startDt.isValid() && todo->hasDueDate()) {
if (todo->allDay()) {
// Days, not seconds, because not all days are 24 hours long.
const auto duration { todo->dtStart(true).daysTo(todo->dtDue(true)) };
dueDt = startDt.addDays(duration);
} else {
const auto duration { todo->dtStart(true).secsTo(todo->dtDue(true)) };
dueDt = startDt.addSecs(duration);
}
}
ret += QLatin1String("<br>")
+i18n("<i>Start:</i> %1", dateToString(startDt.toLocalTime().date(), false));
}
if (todo->hasDueDate()) {
QDateTime dueDt = todo->dtDue();
if (todo->recurs() && date.isValid()) {
QDateTime kdt(date, QTime(0, 0, 0), Qt::LocalTime);
kdt = kdt.addSecs(-1);
dueDt.setDate(todo->recurrence()->getNextDateTime(kdt).date());
}
QString ret;
if (startDt.isValid()) {
ret = QLatin1String("<br>")
% i18nc("To-do's start date", "<i>Start:</i> %1", dateTimeToString(startDt, todo->allDay(), false));
}
if (dueDt.isValid()) {
ret += QLatin1String("<br>")
+i18n("<i>Due:</i> %1",
dateTimeToString(dueDt, todo->allDay(), false));
% i18nc("To-do's due date", "<i>Due:</i> %1", dateTimeToString(dueDt, todo->allDay(), false));
}
// Print priority and completed info here, for lack of a better place
if (todo->priority() > 0) {
ret += QLatin1String("<br>");
ret += QLatin1String("<i>") + i18n("Priority:") + QLatin1String("</i>") + QLatin1String("&nbsp;");
ret += QString::number(todo->priority());
ret += QLatin1String("<br>")
% i18nc("To-do's priority number", "<i>Priority:</i> %1", QString::number(todo->priority()));
}
ret += QLatin1String("<br>");
if (todo->isCompleted()) {
ret += QLatin1String("<i>") + i18nc("Completed: date", "Completed:") + QLatin1String("</i>") + QLatin1String("&nbsp;");
ret += Stringify::todoCompletedDateTime(todo).replace(QLatin1Char(' '), QLatin1String("&nbsp;"));
if (todo->hasCompletedDate()) {
ret += i18nc("To-do's completed date", "<i>Completed:</i> %1", dateTimeToString(todo->completed(), false, false));
} else {
ret += QLatin1String("<i>") + i18n("Percent Done:") + QLatin1String("</i>") + QLatin1String("&nbsp;");
ret += i18n("%1%", todo->percentComplete());
int pct = todo->percentComplete();
if (todo->recurs() && asOfDate.isValid()) {
const QDate recurrenceDate = todo->dtRecurrence().date();
if (recurrenceDate < startDt.date()) {
pct = 0;
} else if (recurrenceDate > startDt.date()) {
pct = 100;
}
}
ret += i18nc("To-do's percent complete:", "<i>Percent Done:</i> %1%", pct);
}
return ret.replace(QLatin1Char(' '), QLatin1String("&nbsp;"));
......
......@@ -77,8 +77,8 @@ namespace IncidenceFormatter {
@param sourceName where the incidence is from (e.g. resource name)
@param incidence is a pointer to the Incidence to be formatted.
@param date is the QDate for which the toolTip should be computed; used
mainly for recurring incidences. Note: For to-dos, this is the due date of
the occurrence, not the start date.
mainly for recurring incidences. Note: For to-dos, this a date between the
start date and the due date (inclusive) of the occurrence.
@param richText if yes, the QString will be created as RichText.
*/
KCALUTILS_EXPORT QString toolTipStr(const QString &sourceName, const KCalendarCore::IncidenceBase::Ptr &incidence, QDate date = QDate(), bool richText = true);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment