Commit 6bfd7309 authored by Glen Ditchfield's avatar Glen Ditchfield 🐛 Committed by Glen Ditchfield
Browse files

Allow inclusion of categories and start dates in the printed to-do list

 * Added check boxes to the configuration dialog to allow inclusion of
   the to-do categories (tags) and start date.
 * Added optional headers and data colums to the print-out.

BUG: 250450

CCBUG: 150685

CCBUG: 195779
parent 860ca0c2
Pipeline #63946 passed with stage
in 5 minutes and 48 seconds
......@@ -1398,6 +1398,8 @@ void CalPrintTodos::readSettingsWidget()
mIncludeDescription = cfg->mDescription->isChecked();
mIncludePriority = cfg->mPriority->isChecked();
mIncludeCategories = cfg->mCategories->isChecked();
mIncludeStartDate = cfg->mStartDate->isChecked();
mIncludeDueDate = cfg->mDueDate->isChecked();
mIncludePercentComplete = cfg->mPercentComplete->isChecked();
mConnectSubTodos = cfg->mConnectSubTodos->isChecked();
......@@ -1427,6 +1429,8 @@ void CalPrintTodos::setSettingsWidget()
cfg->mDescription->setChecked(mIncludeDescription);
cfg->mPriority->setChecked(mIncludePriority);
cfg->mCategories->setChecked(mIncludeCategories);
cfg->mStartDate->setChecked(mIncludeStartDate);
cfg->mDueDate->setChecked(mIncludeDueDate);
cfg->mPercentComplete->setChecked(mIncludePercentComplete);
cfg->mConnectSubTodos->setChecked(mConnectSubTodos);
......@@ -1463,6 +1467,8 @@ void CalPrintTodos::loadConfig()
mTodoPrintType = (eTodoPrintType)grp.readEntry("Print type", static_cast<int>(TodosAll));
mIncludeDescription = grp.readEntry("Include description", true);
mIncludePriority = grp.readEntry("Include priority", true);
mIncludeCategories = grp.readEntry("Include categories", true);
mIncludeStartDate = grp.readEntry("Include start date", true);
mIncludeDueDate = grp.readEntry("Include due date", true);
mIncludePercentComplete = grp.readEntry("Include percentage completed", true);
mConnectSubTodos = grp.readEntry("Connect subtodos", true);
......@@ -1484,6 +1490,8 @@ void CalPrintTodos::saveConfig()
grp.writeEntry("Print type", int(mTodoPrintType));
grp.writeEntry("Include description", mIncludeDescription);
grp.writeEntry("Include priority", mIncludePriority);
grp.writeEntry("Include categories", mIncludeCategories);
grp.writeEntry("Include start date", mIncludeStartDate);
grp.writeEntry("Include due date", mIncludeDueDate);
grp.writeEntry("Include percentage completed", mIncludePercentComplete);
grp.writeEntry("Connect subtodos", mConnectSubTodos);
......@@ -1497,7 +1505,6 @@ void CalPrintTodos::saveConfig()
void CalPrintTodos::print(QPainter &p, int width, int height)
{
int pospriority = 0;
int possummary = 100;
QRect headerBox(0, 0, width, headerHeight());
......@@ -1520,41 +1527,55 @@ void CalPrintTodos::print(QPainter &p, int width, int height)
p.setFont(QFont(QStringLiteral("sans-serif"), 9, QFont::Bold));
int lineSpacing = p.fontMetrics().lineSpacing();
mCurrentLinePos += lineSpacing;
int pospriority = -1;
if (mIncludePriority) {
outStr += i18n("Priority");
pospriority = 0;
p.drawText(pospriority, mCurrentLinePos - 2, outStr);
} else {
pospriority = -1;
}
int posdue;
int posSoFar = width; // Position of leftmost optional header.
int posdue = -1;
if (mIncludeDueDate) {
outStr.truncate(0);
outStr += i18nc("@label to-do due date", "Due");
const int widDue = std::max(p.fontMetrics().boundingRect(outStr).width(), widDate);
posdue = width - widDue;
posdue = posSoFar - widDue;
p.drawText(posdue, mCurrentLinePos - 2, outStr);
} else {
posdue = -1;
posSoFar = posdue;
}
int posStart = -1;
if (mIncludeStartDate) {
outStr.truncate(0);
outStr += i18nc("@label to-do start date", "Start");
const int widStart = std::max(p.fontMetrics().boundingRect(outStr).width(), widDate);
posStart = posSoFar - widStart - 5;
p.drawText(posStart, mCurrentLinePos - 2, outStr);
posSoFar = posStart;
}
int poscomplete;
int poscomplete = -1;
if (mIncludePercentComplete) {
outStr.truncate(0);
outStr += i18nc("@label to-do percentage complete", "Complete");
const int widComplete = std::max(p.fontMetrics().boundingRect(outStr).width(), widPct);
if (!mIncludeDueDate) {
poscomplete = width - widComplete;
} else {
poscomplete = posdue - widComplete - 5;
}
poscomplete = posSoFar - widComplete - 5;
p.drawText(poscomplete, mCurrentLinePos - 2, outStr);
} else {
poscomplete = -1;
posSoFar = poscomplete;
}
int posCategories = -1;
if (mIncludeCategories) {
outStr.truncate(0);
outStr += i18nc("@label to-do categories", "Tags");
const int widCats = std::max(p.fontMetrics().boundingRect(outStr).width(), 100); // Arbitrary!
posCategories = posSoFar - widCats - 5;
p.drawText(posCategories, mCurrentLinePos - 2, outStr);
}
p.setFont(QFont(QStringLiteral("sans-serif"), 10));
// fontHeight = p.fontMetrics().height();
KCalendarCore::Todo::List todoList;
KCalendarCore::Todo::List tempList;
......@@ -1631,7 +1652,7 @@ void CalPrintTodos::print(QPainter &p, int width, int height)
// Skip sub-to-dos. They will be printed recursively in drawTodo()
if (todo->relatedTo().isEmpty()) { // review(AKONADI_PORT)
count++;
drawTodo(count,
drawTodo2(count,
todo,
p,
sortField,
......@@ -1641,6 +1662,8 @@ void CalPrintTodos::print(QPainter &p, int width, int height)
mIncludeDescription,
pospriority,
possummary,
posCategories,
posStart,
posdue,
poscomplete,
0,
......
......@@ -296,6 +296,8 @@ protected:
bool mIncludeDescription;
bool mIncludePriority;
bool mIncludeCategories;
bool mIncludeStartDate;
bool mIncludeDueDate;
bool mIncludePercentComplete;
bool mConnectSubTodos;
......
......@@ -1898,9 +1898,38 @@ void CalPrintPluginBase::drawTodo(int &count,
TodoParentStart *r,
bool excludeConfidential,
bool excludePrivate)
{
drawTodo2(count, todo, p, sortField, sortDir, connectSubTodos, strikeoutCompleted,
desc, posPriority, posSummary, -1, -1, posDueDt, posPercentComplete,
level, x, y, width, pageHeight, todoList, r, excludeConfidential, excludePrivate);
}
void CalPrintPluginBase::drawTodo2(int &count,
const KCalendarCore::Todo::Ptr &todo,
QPainter &p,
KCalendarCore::TodoSortField sortField,
KCalendarCore::SortDirection sortDir,
bool connectSubTodos,
bool strikeoutCompleted,
bool desc,
int posPriority,
int posSummary,
int posCategories,
int posStartDt,
int posDueDt,
int posPercentComplete,
int level,
int x,
int &y,
int width,
int pageHeight,
const KCalendarCore::Todo::List &todoList,
TodoParentStart *r,
bool excludeConfidential,
bool excludePrivate)
{
QString outStr;
const auto local = QLocale::system();
const auto locale = QLocale::system();
QRect rect;
TodoParentStart startpt;
// This list keeps all starting points of the parent to-dos so the connection
......@@ -1912,20 +1941,10 @@ void CalPrintPluginBase::drawTodo(int &count,
y += 10;
// Compute the right hand side of the to-do box
int rhs = posPercentComplete;
if (rhs < 0) {
rhs = posDueDt; // not printing percent completed
}
if (rhs < 0) {
rhs = x + width; // not printing due dates either
}
int left = posSummary + (level * 10);
// If this is a sub-to-do, r will not be 0, and we want the LH side
// of the priority line up to the RH side of the parent to-do's priority
bool showPriority = posPriority >= 0;
int lhs = posPriority;
if (r) {
lhs = r->mRect.right() + 1;
......@@ -1936,6 +1955,7 @@ void CalPrintPluginBase::drawTodo(int &count,
// Make it a more reasonable size
rect.setWidth(18);
rect.setHeight(18);
const int top = rect.top();
// Draw a checkbox
p.setBrush(QBrush(Qt::NoBrush));
......@@ -1948,7 +1968,7 @@ void CalPrintPluginBase::drawTodo(int &count,
lhs = rect.right() + 5;
// Priority
if (todo->priority() > 0 && showPriority) {
if (posPriority >= 0 && todo->priority() > 0) {
p.drawText(rect, Qt::AlignCenter, outStr);
}
startpt.mRect = rect; // save for later
......@@ -1968,48 +1988,74 @@ void CalPrintPluginBase::drawTodo(int &count,
p.drawLine(center, bottom, center, to);
}
// summary
outStr = todo->summary();
rect = p.boundingRect(lhs, rect.top(), (rhs - (left + rect.width() + 5)), -1, Qt::TextWordWrap, outStr);
int posSoFar = width; // Position of leftmost optional field.
QRect newrect;
QFont newFont(p.font());
QFont oldFont(p.font());
if (todo->isCompleted() && strikeoutCompleted) {
newFont.setStrikeOut(true);
p.setFont(newFont);
}
p.drawText(rect, Qt::TextWordWrap, outStr, &newrect);
p.setFont(oldFont);
// due date
if (todo->hasDueDate() && posDueDt >= 0) {
outStr = local.toString(todo->dtDue().toLocalTime().date(), QLocale::ShortFormat);
rect = p.boundingRect(posDueDt, y, x + width, -1, Qt::AlignTop | Qt::AlignLeft, outStr);
if (posDueDt >= 0 && todo->hasDueDate()) {
outStr = locale.toString(todo->dtDue().toLocalTime().date(), QLocale::ShortFormat);
rect = p.boundingRect(posDueDt, top, x + width, -1, Qt::AlignTop | Qt::AlignLeft, outStr);
p.drawText(rect, Qt::AlignTop | Qt::AlignLeft, outStr);
posSoFar = posDueDt;
}
// start date
if (posStartDt >= 0 && todo->hasStartDate()) {
outStr = locale.toString(todo->dtStart().toLocalTime().date(), QLocale::ShortFormat);
rect = p.boundingRect(posStartDt, top, x + width, -1, Qt::AlignTop | Qt::AlignLeft, outStr);
p.drawText(rect, Qt::AlignTop | Qt::AlignLeft, outStr);
posSoFar = posStartDt;
}
// percentage completed
bool showPercentComplete = posPercentComplete >= 0;
if (showPercentComplete) {
if (posPercentComplete >= 0) {
int lwidth = 24;
int lheight = p.fontMetrics().ascent();
// first, draw the progress bar
int progress = static_cast<int>(((lwidth * todo->percentComplete()) / 100.0 + 0.5));
p.setBrush(QBrush(Qt::NoBrush));
p.drawRect(posPercentComplete, y + 3, lwidth, lheight);
p.drawRect(posPercentComplete, top, lwidth, lheight);
if (progress > 0) {
p.setBrush(QColor(128, 128, 128));
p.drawRect(posPercentComplete, y + 3, progress, lheight);
p.drawRect(posPercentComplete, top, progress, lheight);
}
// now, write the percentage
outStr = i18n("%1%", todo->percentComplete());
rect = p.boundingRect(posPercentComplete + lwidth + 3, y, x + width, -1, Qt::AlignTop | Qt::AlignLeft, outStr);
rect = p.boundingRect(posPercentComplete + lwidth + 3, top, x + width, -1, Qt::AlignTop | Qt::AlignLeft, outStr);
p.drawText(rect, Qt::AlignTop | Qt::AlignLeft, outStr);
posSoFar = posPercentComplete;
}
// categories
QRect categoriesRect {0, 0, 0, 0};
if (posCategories >= 0) {
outStr = todo->categoriesStr();
outStr.replace(QLatin1Char(','), QLatin1Char('\n'));
rect = p.boundingRect(posCategories, top, posSoFar - posCategories, -1, Qt::TextWordWrap, outStr);
p.drawText(rect, Qt::TextWordWrap, outStr, &categoriesRect);
posSoFar = posCategories;
}
// summary
outStr = todo->summary();
rect = p.boundingRect(lhs, top, posSoFar - lhs - 5, -1, Qt::TextWordWrap, outStr);
QFont oldFont(p.font());
if (strikeoutCompleted && todo->isCompleted()) {
QFont newFont(p.font());
newFont.setStrikeOut(true);
p.setFont(newFont);
}
QRect summaryRect;
p.drawText(rect, Qt::TextWordWrap, outStr, &summaryRect);
p.setFont(oldFont);
y = std::max(categoriesRect.bottom(), summaryRect.bottom());
y = newrect.bottom();
// description
if (desc && !todo->description().isEmpty()) {
drawTodoLines(p, todo->description(), left, y, width - (left + 10 - x), pageHeight, todo->descriptionIsRich(), startPoints, connectSubTodos);
}
// Make a list of all the sub-to-dos related to this to-do.
KCalendarCore::Todo::List t;
......@@ -2050,11 +2096,6 @@ void CalPrintPluginBase::drawTodo(int &count,
startpt.mHasLine = (relations.size() > 0);
startPoints.append(&startpt);
// description
if (!todo->description().isEmpty() && desc) {
drawTodoLines(p, todo->description(), left, y, width - (left + 10 - x), pageHeight, todo->descriptionIsRich(), startPoints, connectSubTodos);
}
// Sort the sub-to-dos and print them
#ifdef AKONADI_PORT_DISABLED
KCalendarCore::Todo::List sl = mCalendar->sortTodos(&t, sortField, sortDir);
......@@ -2073,7 +2114,7 @@ void CalPrintPluginBase::drawTodo(int &count,
if (++subcount == sl.size()) {
startpt.mHasLine = false;
}
drawTodo(count,
drawTodo2(count,
isl,
p,
sortField,
......@@ -2083,6 +2124,8 @@ void CalPrintPluginBase::drawTodo(int &count,
desc,
posPriority,
posSummary,
posCategories,
posStartDt,
posDueDt,
posPercentComplete,
level + 1,
......
......@@ -162,6 +162,7 @@ public:
@param str The text to be printed in the box
*/
void printEventString(QPainter &p, const QRect &box, const QString &str, int flags = -1);
/**
Print the box for the given event with the given string.
@param p QPainter of the printout
......@@ -282,6 +283,7 @@ public:
@param box coordinates of the box for the days of the week
*/
void drawDaysOfWeek(QPainter &p, const QDate &fromDate, const QDate &toDate, const QRect &box);
/**
Draw a single weekday name in a box inside the given area of the painter.
This is called in a loop by drawDaysOfWeek.
......@@ -330,6 +332,7 @@ public:
const QRect &box,
bool excludeConfidential,
bool excludePrivate);
/**
Draw the agenda box for the day print style (the box showing all events of that day).
Also draws a grid with half-hour spacing of the grid lines.
......@@ -410,6 +413,7 @@ public:
bool includeDescription = false,
bool excludeDescription = true,
bool excludePrivate = true);
/**
Draw the week (filofax) table of the week containing the date qd. The first
three days of the week will be shown in the first column (using drawDayBox),
......@@ -436,6 +440,7 @@ public:
bool includeDescription,
bool excludeConfidential,
bool excludePrivate);
/**
Draw the (filofax) table for a bunch of days, using drawDayBox.
@param p QPainter of the printout
......@@ -461,6 +466,7 @@ public:
bool includeDescription,
bool excludeConfidential,
bool excludePrivate);
/**
Draw the timetable view of the given time range from fromDate to toDate.
On the left side the time scale is printed (using drawTimeLine), then each
......@@ -526,6 +532,7 @@ public:
bool excludeConfidential,
bool excludePrivate,
const QRect &box);
/**
Draw a vertical representation of the month containing the date dt. Each
day gets one line.
......@@ -558,7 +565,32 @@ public:
class TodoParentStart;
/**
Draws single to-do and its (intented) sub-to-dos, optionally connects them
* @see drawTodo2().
*/
void drawTodo(int &count,
const KCalendarCore::Todo::Ptr &todo,
QPainter &p,
KCalendarCore::TodoSortField sortField,
KCalendarCore::SortDirection sortDir,
bool connectSubTodos,
bool strikeoutCompleted,
bool desc,
int posPriority,
int posSummary,
int posDueDt,
int posPercentComplete,
int level,
int x,
int &y,
int width,
int pageHeight,
const KCalendarCore::Todo::List &todoList,
TodoParentStart *r,
bool excludeConfidential,
bool excludePrivate);
/**
Draws single to-do and its (indented) sub-to-dos, optionally connects them
by a tree-like line, and optionally shows due date, summary, description
and priority.
@param count The number of the currently printed to-do (count will be
......@@ -575,13 +607,17 @@ public:
@param desc Whether to print the whole description of the to-do
(the summary is always printed).
@param posPriority x-coordinate where the priority is supposed to be
printed. If <0, no priority will be printed.
printed. If negative, no priority will be printed.
@param posSummary x-coordinate where the summary of the to-do is supposed
to be printed.
@param posCategories x-coordinate where the categories (tags) should be
printed. If negative, no categories will be printed.
@param posStartDt x-coordinate where the due date is supposed to the be
printed. If negative, no start date will be printed.
@param posDueDt x-coordinate where the due date is supposed to the be
printed. If <0, no due date will be printed.
printed. If negative, no due date will be printed.
@param posPercentComplete x-coordinate where the percentage complete is
supposed to be printed. If <0, percentage complete will not be printed.
supposed to be printed. If negative, percentage complete will not be printed.
@param level Level of the current to-do in the to-do hierarchy (0 means
highest level of printed to-dos, 1 are their sub-to-dos, etc.)
@param x x-coordinate of the upper left coordinate of the first to-do.
......@@ -593,7 +629,7 @@ public:
@param r Internal (used when printing sub-to-dos to give information
about its parent)
*/
void drawTodo(int &count,
void drawTodo2(int &count,
const KCalendarCore::Todo::Ptr &todo,
QPainter &p,
KCalendarCore::TodoSortField sortField,
......@@ -603,6 +639,8 @@ public:
bool desc,
int posPriority,
int posSummary,
int posCategories,
int posStartDt,
int posDueDt,
int posPercentComplete,
int level,
......@@ -626,6 +664,7 @@ public:
would be below that line, a new page is started.
*/
void drawJournal(const KCalendarCore::Journal::Ptr &journal, QPainter &p, int x, int &y, int width, int pageHeight);
/**
Draws text lines splitting on page boundaries.
@param p QPainter of the printout
......
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<author>Reinhold Kainhofer &lt;reinhold@kainhofer.com&gt;</author>
<comment>Configuration page for the print day mode.</comment>
<comment>Configuration page for the print todo mode.</comment>
<class>CalPrintTodoConfig_Base</class>
<widget class="QWidget" name="CalPrintTodoConfig_Base">
<property name="geometry">
......@@ -87,7 +87,7 @@ p, li { white-space: pre-wrap; }
<bool>true</bool>
</property>
<property name="text">
<string>Print unfinished to-dos onl&amp;y</string>
<string>Print &amp;uncompleted to-dos only</string>
</property>
</widget>
</item>
......@@ -256,7 +256,7 @@ p, li { white-space: pre-wrap; }
<string>Check this option to exclude confidential events.</string>
</property>
<property name="text">
<string>Exclude c&amp;onfidential</string>
<string>Exclude &amp;confidential</string>
</property>
</widget>
</item>
......@@ -294,12 +294,31 @@ p, li { white-space: pre-wrap; }
<string>Check this option if you want to see the item descriptions printed.</string>
</property>
<property name="text">
<string>Include &amp;descriptions</string>
<string>&amp;Description</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="mCategories">
<property name="toolTip">
<string>Print item tags</string>
</property>
<property name="whatsThis">
<string>Check this option if you want to see the item tags printed.</string>
</property>
<property name="text">
<string>Ta&amp;gs</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="mPriority">
<property name="toolTip">
<string>Print item priorities</string>
</property>
<property name="whatsThis">
<string>Check this option if you want to see the item priorities printed.</string>
</property>
<property name="text">
<string>&amp;Priority</string>
</property>
......@@ -309,12 +328,28 @@ p, li { white-space: pre-wrap; }
</widget>
</item>
<item>
<widget class="QCheckBox" name="mDueDate">
<widget class="QCheckBox" name="mStartDate">
<property name="toolTip">
<string>Print item start dates</string>
</property>
<property name="whatsThis">
<string>Check this option if you want to see the item start dates (when work can begin) printed.</string>
</property>
<property name="text">
<string>Due date</string>
<string>&amp;Start date</string>
</property>
<property name="shortcut">
<string/>
</widget>
</item>
<item>
<widget class="QCheckBox" name="mDueDate">
<property name="toolTip">
<string>Print item due dates</string>
</property>
<property name="whatsThis">
<string>Check this option if you want to see the item due dates printed.</string>
</property>
<property name="text">
<string>Du&amp;e date</string>
</property>
<property name="checked">
<bool>true</bool>
......@@ -323,8 +358,14 @@ p, li { white-space: pre-wrap; }
</item>
<item>
<widget class="QCheckBox" name="mPercentComplete">
<property name="toolTip">
<string>Print item completion percentage</string>
</property>
<property name="whatsThis">
<string>Check this option if you want to see the item completion percentage printed as a number and bar graph.</string>
</property>
<property name="text">
<string>Per&amp;centage completed</string>
<string>Percentage co&amp;mpleted</string>
</property>
<property name="checked">
<bool>true</bool>
......@@ -333,6 +374,8 @@ p, li { white-space: pre-wrap; }
</item>
</layout>
<zorder>mDescription</zorder>
<zorder>mCategories</zorder>
<zorder>mStartDate</zorder>
<zorder>mDueDate</zorder>
<zorder>mPercentComplete</zorder>
<zorder>mPriority</zorder>
......@@ -423,7 +466,7 @@ p, li { white-space: pre-wrap; }
<item>
<widget class="QCheckBox" name="mStrikeOutCompleted">
<property name="text">
<string>Strike &amp;out completed to-do summaries</string>
<string>Stri&amp;ke out completed to-do summaries</string>
</property>
<property name="checked">
<bool>true</bool>
......@@ -475,14 +518,19 @@ p, li { white-space: pre-wrap; }
<tabstop>mPrintDueRange</tabstop>
<tabstop>mFromDate</tabstop>
<tabstop>mToDate</tabstop>
<tabstop>mExcludeConfidential</tabstop>
<tabstop>mExcludePrivate</tabstop>
<tabstop>mDescription</tabstop>
<tabstop>mCategories</tabstop>