mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-24 10:52:52 +00:00
1419 lines
49 KiB
C++
1419 lines
49 KiB
C++
/*
|
|
This file is part of the PimPrint library.
|
|
|
|
Copyright (C) 2012-2013 Allen Winter <winter@kde.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 "calprintbase.h"
|
|
|
|
#include <calendarsupport/kcalprefs.h>
|
|
#include <calendarsupport/utils.h>
|
|
|
|
#include <KCalendarSystem>
|
|
#include <KGlobal>
|
|
#include <KSystemTimeZones>
|
|
|
|
#include <QAbstractTextDocumentLayout>
|
|
#include <QPrinter>
|
|
#include <QTextCursor>
|
|
#include <QTextDocument>
|
|
#include <QTextDocumentFragment>
|
|
#include <boost/concept_check.hpp>
|
|
|
|
using namespace PimPrint::Calendar;
|
|
|
|
//TODO: compute default page height and width based QPainter window
|
|
static int sPortraitPageHeight = 792; // page height, for portrait orientation
|
|
static int sLandscapePageHeight = 612; // page height, for landscape orientation
|
|
|
|
static int sPortraitHeaderHeight = 72; // header height, for portrait orientation
|
|
static int sLandscapeHeaderHeight = 54; // header height, for landscape orientation
|
|
static int sSubHeaderHeight = 20; // subheader height, for all orientations
|
|
|
|
static int sPortraitFooterHeight = 16; // footer height, for portrait orientation
|
|
static int sLandscapeFooterHeight = 14; // footer height, for landscape orientation
|
|
|
|
static int sMarginSize = 36; // margins, for all orientations (.5 inch)
|
|
static int sPaddingSize = 7; // padding between the various top-level boxes
|
|
|
|
static int sBoxBorderWidth = 2; // width of the border of all top-level boxes
|
|
static int sItemBoxBorderWidth = 0; // width of the border of all item boxes
|
|
static int sTimeLineWidth = 50; // width of timeline (eg. day and timetable)
|
|
|
|
/**
|
|
Private class that helps to provide binary compatibility between releases.
|
|
@internal
|
|
*/
|
|
//@cond PRIVATE
|
|
class PimPrint::Calendar::CalPrintBase::Private
|
|
{
|
|
public:
|
|
Private()
|
|
: mPrinter(0),
|
|
mPageHeight(-1),
|
|
mPageWidth(-1),
|
|
mCalendar(0),
|
|
mCalSystem(0),
|
|
mPrintStyle(CalPrintBase::None),
|
|
mHeaderHeight(-1),
|
|
mSubHeaderHeight(sSubHeaderHeight),
|
|
mFooterHeight(-1),
|
|
mMargins(sMarginSize),
|
|
mPadding(sPaddingSize),
|
|
mBoxBorderWidth(sBoxBorderWidth),
|
|
mItemBoxBorderWidth(sItemBoxBorderWidth),
|
|
mTimeLineWidth(sTimeLineWidth),
|
|
mInfoOptions(0),
|
|
mTypeOptions(0),
|
|
mRangeOptions(0),
|
|
mExtraOptions(0),
|
|
mUseColor(true),
|
|
mUseLandscape(false),
|
|
mPrintFooter(false)
|
|
{
|
|
}
|
|
|
|
QPrinter *mPrinter; // the QPrinter
|
|
QPainter mPainter; // the QPainter
|
|
int mPageHeight; // page height, depends on page orientation
|
|
int mPageWidth; // page height, depends on page orientation
|
|
KCalCore::Calendar::Ptr mCalendar; // the Calendar
|
|
KCalendarSystem *mCalSystem; // the Calendar System
|
|
CalPrintBase::Style mPrintStyle; // the style to print
|
|
int mHeaderHeight; // height of header, depends on page orientation
|
|
int mSubHeaderHeight; // subheader height, same for all orientations
|
|
int mFooterHeight; // height of footer, depends on page orientation
|
|
int mMargins; // margins, for all orientations
|
|
int mPadding; // padding between the various top-level boxes
|
|
int mBoxBorderWidth; // width of the border of all top-level boxes
|
|
int mItemBoxBorderWidth; // width of the border of all item boxes
|
|
int mTimeLineWidth; // width of timelines
|
|
|
|
InfoOptions mInfoOptions; // flags for information to print.
|
|
TypeOptions mTypeOptions; // flags for types to print.
|
|
RangeOptions mRangeOptions; // flags for time ranges to print.
|
|
ExtraOptions mExtraOptions; // flags for extra stuff to print.
|
|
bool mUseColor; // flag, print in color
|
|
bool mUseLandscape; // flag, print in landscape orientation
|
|
bool mPrintFooter; // flag, print footer
|
|
};
|
|
//@endcond
|
|
|
|
CalPrintBase::CalPrintBase(QPrinter *printer)
|
|
: d(new PimPrint::Calendar::CalPrintBase::Private)
|
|
{
|
|
init(printer);
|
|
}
|
|
|
|
CalPrintBase::~CalPrintBase()
|
|
{
|
|
finish();
|
|
delete d;
|
|
}
|
|
|
|
void CalPrintBase::init(QPrinter *printer) const
|
|
{
|
|
if (!printer) {
|
|
return;
|
|
}
|
|
|
|
// Init printer
|
|
d->mPrinter = printer;
|
|
d->mPrinter->setColorMode(QPrinter::GrayScale);
|
|
|
|
// Init painter
|
|
d->mPainter.begin(d->mPrinter);
|
|
|
|
// FIXME: allow each margin to be set individually.
|
|
// the painter initially begins at 72 dpi per the Qt docs.
|
|
// Currently hard-coding half-inch margins (36 dpi)
|
|
const int margin = margins();
|
|
d->mPainter.setViewport(margin, margin,
|
|
d->mPainter.viewport().width() - 2 * margin,
|
|
d->mPainter.viewport().height() - 2 * margin);
|
|
|
|
// Init page
|
|
setPageHeight(d->mPainter.window().height());
|
|
setPageWidth(d->mPainter.window().width());
|
|
}
|
|
|
|
void CalPrintBase::finish() const
|
|
{
|
|
d->mPainter.end();
|
|
d->mPrinter = 0;
|
|
}
|
|
|
|
void CalPrintBase::setThePrinter(QPrinter *printer)
|
|
{
|
|
d->mPrinter = printer;
|
|
}
|
|
|
|
QPrinter *CalPrintBase::thePrinter() const
|
|
{
|
|
return d->mPrinter;
|
|
}
|
|
|
|
void CalPrintBase::setPrintCalendar(const KCalCore::Calendar::Ptr &calendar)
|
|
{
|
|
d->mCalendar = calendar;
|
|
}
|
|
|
|
KCalCore::Calendar::Ptr CalPrintBase::printCalendar() const
|
|
{
|
|
return d->mCalendar;
|
|
}
|
|
|
|
void CalPrintBase::setCalendarSystem(KCalendarSystem *calSystem)
|
|
{
|
|
d->mCalSystem = calSystem;
|
|
}
|
|
|
|
KCalendarSystem *CalPrintBase::calendarSystem() const
|
|
{
|
|
return d->mCalSystem;
|
|
}
|
|
|
|
void CalPrintBase::setPrintStyle(const Style style)
|
|
{
|
|
d->mPrintStyle = style;
|
|
}
|
|
|
|
CalPrintBase::Style CalPrintBase::printStyle() const
|
|
{
|
|
return d->mPrintStyle;
|
|
}
|
|
|
|
void CalPrintBase::setPageHeight(const int height) const
|
|
{
|
|
d->mPageHeight = height;
|
|
}
|
|
|
|
int CalPrintBase::pageHeight() const
|
|
{
|
|
if (d->mPageHeight >= 0) {
|
|
return d->mPageHeight;
|
|
} else if (!d->mUseLandscape) {
|
|
return sPortraitPageHeight; //TODO: replace with p.window().height()
|
|
} else {
|
|
return sLandscapePageHeight; //TODO: replace with p.window().width()
|
|
}
|
|
}
|
|
|
|
void CalPrintBase::setPageWidth(const int width) const
|
|
{
|
|
d->mPageWidth = width;
|
|
}
|
|
|
|
int CalPrintBase::pageWidth() const
|
|
{
|
|
if (d->mPageWidth >= 0) {
|
|
return d->mPageWidth;
|
|
} else if (d->mUseLandscape) {
|
|
return sPortraitPageHeight; //TODO: replace with p.window().height()
|
|
} else {
|
|
return sLandscapePageHeight; //TODO: replace with p.windows().width()
|
|
}
|
|
}
|
|
|
|
void CalPrintBase::setUseLandscape(const bool useLandscape)
|
|
{
|
|
d->mUseLandscape = useLandscape;
|
|
}
|
|
|
|
bool CalPrintBase::useLandscape() const
|
|
{
|
|
return d->mUseLandscape;
|
|
}
|
|
|
|
void CalPrintBase::setUseColor(const bool useColor)
|
|
{
|
|
d->mUseColor = useColor;
|
|
}
|
|
|
|
bool CalPrintBase::useColor() const
|
|
{
|
|
return d->mUseColor;
|
|
}
|
|
|
|
void CalPrintBase::setHeaderHeight(const int height)
|
|
{
|
|
d->mHeaderHeight = height;
|
|
}
|
|
|
|
int CalPrintBase::headerHeight() const
|
|
{
|
|
if (d->mHeaderHeight >= 0) {
|
|
return d->mHeaderHeight;
|
|
} else if (!d->mUseLandscape) {
|
|
return sPortraitHeaderHeight;
|
|
} else {
|
|
return sLandscapeHeaderHeight;
|
|
}
|
|
}
|
|
|
|
void CalPrintBase::setSubHeaderHeight(const int height)
|
|
{
|
|
d->mSubHeaderHeight = height;
|
|
}
|
|
|
|
int CalPrintBase::subHeaderHeight() const
|
|
{
|
|
return d->mSubHeaderHeight;
|
|
}
|
|
|
|
void CalPrintBase::setFooterHeight(const int height)
|
|
{
|
|
d->mFooterHeight = height;
|
|
}
|
|
|
|
int CalPrintBase::footerHeight() const
|
|
{
|
|
if (!d->mPrintFooter) {
|
|
return 0;
|
|
}
|
|
|
|
if (d->mFooterHeight >= 0) {
|
|
return d->mFooterHeight;
|
|
} else if (!d->mUseLandscape) {
|
|
return sPortraitFooterHeight;
|
|
} else {
|
|
return sLandscapeFooterHeight;
|
|
}
|
|
}
|
|
|
|
void CalPrintBase::setPadding(const int padding)
|
|
{
|
|
d->mPadding = padding;
|
|
}
|
|
|
|
int CalPrintBase::padding() const
|
|
{
|
|
return d->mPadding;
|
|
}
|
|
|
|
int CalPrintBase::margins() const
|
|
{
|
|
return d->mMargins;
|
|
}
|
|
|
|
int CalPrintBase::boxBorderWidth() const
|
|
{
|
|
return d->mBoxBorderWidth;
|
|
}
|
|
|
|
int CalPrintBase::itemBoxBorderWidth() const
|
|
{
|
|
return d->mItemBoxBorderWidth;
|
|
}
|
|
|
|
int CalPrintBase::timeLineWidth() const
|
|
{
|
|
return d->mTimeLineWidth;
|
|
}
|
|
|
|
void CalPrintBase::setInfoOptions(CalPrintBase::InfoOptions flags)
|
|
{
|
|
d->mInfoOptions = flags;
|
|
}
|
|
|
|
CalPrintBase::InfoOptions CalPrintBase::infoOptions() const
|
|
{
|
|
return d->mInfoOptions;
|
|
}
|
|
|
|
void CalPrintBase::setTypeOptions(CalPrintBase::TypeOptions flags)
|
|
{
|
|
d->mTypeOptions = flags;
|
|
}
|
|
|
|
CalPrintBase::TypeOptions CalPrintBase::typeOptions() const
|
|
{
|
|
return d->mTypeOptions;
|
|
}
|
|
|
|
void CalPrintBase::setRangeOptions(CalPrintBase::RangeOptions flags)
|
|
{
|
|
d->mRangeOptions = flags;
|
|
}
|
|
|
|
CalPrintBase::RangeOptions CalPrintBase::rangeOptions() const
|
|
{
|
|
return d->mRangeOptions;
|
|
}
|
|
|
|
void CalPrintBase::setExtraOptions(CalPrintBase::ExtraOptions flags)
|
|
{
|
|
d->mExtraOptions = flags;
|
|
}
|
|
|
|
CalPrintBase::ExtraOptions CalPrintBase::extraOptions() const
|
|
{
|
|
return d->mExtraOptions;
|
|
}
|
|
|
|
void CalPrintBase::drawBox(QPainter &p, const int linewidth, const QRect &rect) const
|
|
{
|
|
QPen pen(p.pen());
|
|
QPen oldpen(pen);
|
|
// no border
|
|
if (linewidth >= 0) {
|
|
pen.setWidth(linewidth);
|
|
p.setPen(pen);
|
|
} else {
|
|
p.setPen(Qt::NoPen);
|
|
}
|
|
p.drawRect(rect);
|
|
p.setPen(oldpen);
|
|
}
|
|
|
|
void CalPrintBase::drawShadedBox(QPainter &p, const int linewidth,
|
|
const QBrush &brush, const QRect &rect) const
|
|
{
|
|
QBrush oldbrush(p.brush());
|
|
p.setBrush(brush);
|
|
drawBox(p, linewidth, rect);
|
|
p.setBrush(oldbrush);
|
|
}
|
|
|
|
void CalPrintBase::drawItemString(QPainter &p, const QRect &box,
|
|
const QString &str, int flags) const
|
|
{
|
|
QRect newbox(box);
|
|
newbox.adjust(3, 1, -1, -1);
|
|
p.drawText(newbox, (flags == -1) ?
|
|
(Qt::AlignTop | Qt::AlignLeft | Qt::TextWordWrap) : flags, str);
|
|
}
|
|
|
|
void CalPrintBase::drawItemBox(QPainter &p, const int linewidth, const QRect &box,
|
|
const KCalCore::Incidence::Ptr &incidence,
|
|
const QString &str, int flags) const
|
|
{
|
|
QPen oldpen(p.pen());
|
|
QBrush oldbrush(p.brush());
|
|
QColor bgColor(categoryBgColor(incidence));
|
|
if (d->mUseColor & bgColor.isValid()) {
|
|
p.setBrush(bgColor);
|
|
} else {
|
|
p.setBrush(QColor(232, 232, 232));
|
|
}
|
|
drawBox(p, (linewidth > 0) ? linewidth : itemBoxBorderWidth(), box);
|
|
if (d->mUseColor && bgColor.isValid()) {
|
|
p.setPen(getTextColor(bgColor));
|
|
}
|
|
drawItemString(p, box, str, flags);
|
|
p.setPen(oldpen);
|
|
p.setBrush(oldbrush);
|
|
}
|
|
|
|
void CalPrintBase::drawVerticalBox(QPainter &p, const int linewidth,
|
|
const QRect &box,
|
|
const QString &str, int flags) const
|
|
{
|
|
p.save();
|
|
p.rotate(-90);
|
|
QRect rotatedBox(-box.top() - box.height(), box.left(), box.height(), box.width());
|
|
drawItemBox(p, linewidth, rotatedBox, KCalCore::Incidence::Ptr(), str,
|
|
(flags == -1) ? Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine : flags);
|
|
|
|
p.restore();
|
|
}
|
|
|
|
void CalPrintBase::drawSmallMonth(QPainter &p, const QDate &date, const QRect &box) const
|
|
{
|
|
int weekdayCol = weekdayColumn(date.dayOfWeek());
|
|
int month = date.month();
|
|
QDate monthDate(QDate(date.year(), date.month(), 1));
|
|
// correct begin of week
|
|
QDate monthDate2(monthDate.addDays(-weekdayCol));
|
|
|
|
double cellWidth = double(box.width()) / double(7);
|
|
int rownr = 3 + (date.daysInMonth() + weekdayCol - 1) / 7;
|
|
// 3 Pixel after month name, 2 after day names, 1 after the calendar
|
|
double cellHeight = (box.height() - 5) / rownr;
|
|
QFont oldFont(p.font());
|
|
//TODO: option for the small month font?
|
|
p.setFont(QFont("sans-serif", int(cellHeight - 2), QFont::Normal));
|
|
|
|
// draw the title
|
|
KCalendarSystem *calSys = calendarSystem();
|
|
if (calSys) {
|
|
QRect titleBox(box);
|
|
titleBox.setHeight(int(cellHeight + 1));
|
|
p.drawText(titleBox, Qt::AlignTop | Qt::AlignHCenter, calSys->monthName(date));
|
|
}
|
|
|
|
// draw days of week
|
|
QRect wdayBox(box);
|
|
wdayBox.setTop(int(box.top() + 3 + cellHeight));
|
|
wdayBox.setHeight(int(2 * cellHeight) - int(cellHeight));
|
|
|
|
if (calSys) {
|
|
for (int col = 0; col < 7; ++col) {
|
|
QString tmpStr = calSys->weekDayName(monthDate2)[0].toUpper();
|
|
wdayBox.setLeft(int(box.left() + col * cellWidth));
|
|
wdayBox.setRight(int(box.left() + (col + 1) * cellWidth));
|
|
p.drawText(wdayBox, Qt::AlignCenter, tmpStr);
|
|
monthDate2 = monthDate2.addDays(1);
|
|
}
|
|
}
|
|
|
|
// draw separator line
|
|
int calStartY = wdayBox.bottom() + 2;
|
|
p.drawLine(box.left(), calStartY, box.right(), calStartY);
|
|
monthDate = monthDate.addDays(-weekdayCol);
|
|
|
|
for (int row = 0; row < (rownr - 2); row++) {
|
|
for (int col = 0; col < 7; col++) {
|
|
if (monthDate.month() == month) {
|
|
QRect dayRect(int(box.left() + col * cellWidth),
|
|
int(calStartY + row * cellHeight), 0, 0);
|
|
dayRect.setRight(int(box.left() + (col + 1) * cellWidth));
|
|
dayRect.setBottom(int(calStartY + (row + 1) * cellHeight));
|
|
p.drawText(dayRect, Qt::AlignCenter, QString::number(monthDate.day()));
|
|
}
|
|
monthDate = monthDate.addDays(1);
|
|
}
|
|
}
|
|
p.setFont(oldFont);
|
|
}
|
|
|
|
int CalPrintBase::drawHeader(QPainter &p, const QRect &allbox,
|
|
const QString &title,
|
|
const QDate &leftMonth, const QDate &rightMonth,
|
|
const bool expand,
|
|
const QColor &backColor) const
|
|
{
|
|
// print previous month for month view, print current for to-do, day and week
|
|
int smallMonthWidth = (allbox.width() / 4) - 10;
|
|
if (smallMonthWidth > 100) {
|
|
smallMonthWidth = 100;
|
|
}
|
|
|
|
QRect box(allbox);
|
|
QRect textRect(allbox);
|
|
|
|
QFont oldFont(p.font());
|
|
//TODO: option for the header font?
|
|
QFont newFont("sans-serif", (textRect.height() < 60) ? 16 : 18, QFont::Bold);
|
|
if (expand) {
|
|
p.setFont(newFont);
|
|
QRect boundingR =
|
|
p.boundingRect(textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextWordWrap, title);
|
|
p.setFont(oldFont);
|
|
int h = boundingR.height();
|
|
if (h > allbox.height()) {
|
|
box.setHeight(h);
|
|
textRect.setHeight(h);
|
|
}
|
|
}
|
|
|
|
QBrush backBrush;
|
|
if (!backColor.isValid()) {
|
|
backBrush.setColor(QColor(232, 232, 232));
|
|
} else {
|
|
backBrush.setColor(backColor);
|
|
}
|
|
|
|
drawShadedBox(p, boxBorderWidth(), backBrush, box);
|
|
|
|
// prev month left, current month centered, next month right
|
|
if (rightMonth.isValid()) {
|
|
const QRect rightMonthBox(box.right() - 10 - smallMonthWidth, box.top(),
|
|
smallMonthWidth, box.height());
|
|
drawSmallMonth(p, QDate(rightMonth.year(), rightMonth.month(), 1), rightMonthBox);
|
|
textRect.setRight(rightMonthBox.left());
|
|
}
|
|
if (leftMonth.isValid()) {
|
|
const QRect leftMonthBox(box.left() + 10, box.top(),
|
|
smallMonthWidth, box.height());
|
|
drawSmallMonth(p, QDate(leftMonth.year(), leftMonth.month(), 1), leftMonthBox);
|
|
textRect.setLeft(leftMonthBox.right());
|
|
}
|
|
|
|
// Set the margins
|
|
p.setFont(newFont);
|
|
p.drawText(textRect, Qt::AlignCenter | Qt::AlignVCenter | Qt::TextWordWrap, title);
|
|
p.setFont(oldFont);
|
|
|
|
return textRect.bottom();
|
|
}
|
|
|
|
void CalPrintBase::drawSubHeader(QPainter &p, const QRect &box, const QString &str) const
|
|
{
|
|
drawShadedBox(p, boxBorderWidth(), QColor(232, 232, 232), box);
|
|
QFont oldfont(p.font());
|
|
//TODO: option for the subheader font?
|
|
p.setFont(QFont("sans-serif", 10, QFont::Bold));
|
|
p.drawText(box, Qt::AlignCenter | Qt::AlignVCenter, str);
|
|
p.setFont(oldfont);
|
|
}
|
|
|
|
int CalPrintBase::drawFooter(QPainter &p, const QRect &footbox) const
|
|
{
|
|
QFont oldfont(p.font());
|
|
//TODO: option for the footer font?
|
|
p.setFont(QFont("sans-serif", 6));
|
|
QFontMetrics fm(p.font());
|
|
QString dateStr =
|
|
KGlobal::locale()->formatDateTime(QDateTime::currentDateTime(), KLocale::LongDate);
|
|
p.drawText(footbox, Qt::AlignCenter | Qt::AlignVCenter | Qt::TextSingleLine,
|
|
i18nc("print date: formatted-datetime", "printed: %1", dateStr));
|
|
p.setFont(oldfont);
|
|
|
|
return footbox.bottom();
|
|
}
|
|
|
|
void CalPrintBase::drawTimeLine(QPainter &p,
|
|
const QTime &startTime, const QTime &endTime,
|
|
const QRect &box) const
|
|
{
|
|
drawBox(p, boxBorderWidth(), box);
|
|
|
|
int totalsecs = startTime.secsTo(endTime);
|
|
float minlen = (float)box.height() * 60. / (float)totalsecs;
|
|
float cellHeight = (60. * (float)minlen);
|
|
float currY = box.top();
|
|
// TODO: Don't use half of the width, but less, for the minutes!
|
|
int xcenter = box.left() + box.width() / 2;
|
|
|
|
QTime curTime(startTime);
|
|
if (startTime.minute() > 30) {
|
|
curTime = QTime(startTime.hour() + 1, 0, 0);
|
|
} else if (startTime.minute() > 0) {
|
|
curTime = QTime(startTime.hour(), 30, 0);
|
|
float yy = currY + minlen * (float)startTime.secsTo(curTime) / 60.;
|
|
p.drawLine(xcenter, (int)yy, box.right(), (int)yy);
|
|
curTime = QTime(startTime.hour() + 1, 0, 0);
|
|
}
|
|
currY += (float(startTime.secsTo(curTime) * minlen) / 60.);
|
|
|
|
while (curTime < endTime) {
|
|
p.drawLine(box.left(), (int)currY, box.right(), (int)currY);
|
|
int newY = (int)(currY + cellHeight / 2.);
|
|
QString numStr;
|
|
if (newY < box.bottom()) {
|
|
QFont oldFont(p.font());
|
|
// draw the time:
|
|
if (!KGlobal::locale()->use12Clock()) {
|
|
p.drawLine(xcenter, (int)newY, box.right(), (int)newY);
|
|
numStr.setNum(curTime.hour());
|
|
//TODO: option for this font?
|
|
if (cellHeight > 30) {
|
|
p.setFont(QFont("sans-serif", 14, QFont::Bold));
|
|
} else {
|
|
p.setFont(QFont("sans-serif", 12, QFont::Bold));
|
|
}
|
|
p.drawText(box.left() + 4, (int)currY + 2,
|
|
box.width() / 2 - 2, (int)cellHeight,
|
|
Qt::AlignTop | Qt::AlignRight, numStr);
|
|
//TODO: option for this font?
|
|
p.setFont(QFont("helvetica", 10, QFont::Normal));
|
|
p.drawText(xcenter + 4, (int)currY + 2,
|
|
box.width() / 2 + 2, (int)(cellHeight / 2) - 3,
|
|
Qt::AlignTop | Qt::AlignLeft, "00");
|
|
} else {
|
|
p.drawLine(box.left(), (int)newY, box.right(), (int)newY);
|
|
QTime time(curTime.hour(), 0);
|
|
numStr = KGlobal::locale()->formatTime(time);
|
|
//TODO: option for this font?
|
|
if (box.width() < 60) {
|
|
p.setFont(QFont("sans-serif", 7, QFont::Bold)); // for weekprint
|
|
} else {
|
|
p.setFont(QFont("sans-serif", 12, QFont::Bold)); // for dayprint
|
|
}
|
|
p.drawText(box.left() + 2, (int)currY + 2, box.width() - 4, (int)cellHeight / 2 - 3,
|
|
Qt::AlignTop | Qt::AlignLeft, numStr);
|
|
}
|
|
currY += cellHeight;
|
|
p.setFont(oldFont);
|
|
} // enough space for half-hour line and time
|
|
if (curTime.secsTo(endTime) > 3600) {
|
|
curTime = curTime.addSecs(3600);
|
|
} else {
|
|
curTime = endTime;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CalPrintBase::drawTimeTable(QPainter &p, const QRect &box,
|
|
const QDate &startDate, const QDate &endDate,
|
|
const QTime &startTime, const QTime &endTime,
|
|
bool expandAll) const
|
|
{
|
|
QTime myStartTime = startTime;
|
|
QTime myEndTime = endTime;
|
|
if (expandAll) {
|
|
QDate curDate(startDate);
|
|
KDateTime::Spec timeSpec = KSystemTimeZones::local();
|
|
while (curDate <= endDate) {
|
|
KCalCore::Event::List eventList = printCalendar()->events(curDate, timeSpec);
|
|
Q_FOREACH (const KCalCore::Event::Ptr &event, eventList) {
|
|
Q_ASSERT(event);
|
|
if (event->allDay()) {
|
|
continue;
|
|
}
|
|
if (event->dtStart().time() < myStartTime) {
|
|
myStartTime = event->dtStart().time();
|
|
}
|
|
if (event->dtEnd().time() > myEndTime) {
|
|
myEndTime = event->dtEnd().time();
|
|
}
|
|
}
|
|
curDate = curDate.addDays(1);
|
|
}
|
|
}
|
|
|
|
// timeline is 1 hour:
|
|
int alldayHeight = (int)(3600. * box.height() / (myStartTime.secsTo(myEndTime) + 3600.));
|
|
|
|
QRect dowBox(box);
|
|
dowBox.setLeft(box.left() + timeLineWidth());
|
|
dowBox.setHeight(d->mSubHeaderHeight);
|
|
drawDaysOfWeek(p, dowBox, startDate, endDate);
|
|
|
|
QRect tlBox(box);
|
|
tlBox.setWidth(timeLineWidth());
|
|
tlBox.setTop(dowBox.bottom() + boxBorderWidth() + alldayHeight);
|
|
drawTimeLine(p, myStartTime, myEndTime, tlBox);
|
|
|
|
// draw each day
|
|
QDate curDate(startDate);
|
|
KDateTime::Spec timeSpec = KSystemTimeZones::local();
|
|
int i = 0;
|
|
double cellWidth = double(dowBox.width()) / double(startDate.daysTo(endDate) + 1);
|
|
const QList<QDate> workDays = CalendarSupport::workDays(startDate, endDate);
|
|
while (curDate <= endDate) {
|
|
QRect allDayBox(dowBox.left() + int(i * cellWidth),
|
|
dowBox.bottom() + boxBorderWidth(),
|
|
int((i + 1) * cellWidth) - int(i * cellWidth),
|
|
alldayHeight);
|
|
QRect dayBox(allDayBox);
|
|
dayBox.setTop(tlBox.top());
|
|
dayBox.setBottom(box.bottom());
|
|
KCalCore::Event::List eventList =
|
|
printCalendar()->events(curDate, timeSpec,
|
|
KCalCore::EventSortStartDate,
|
|
KCalCore::SortDirectionAscending);
|
|
|
|
alldayHeight = drawAllDayBox(p, allDayBox, curDate, eventList);
|
|
|
|
drawAgendaDayBox(p, dayBox, curDate, eventList, myStartTime, myEndTime, workDays);
|
|
|
|
i++;
|
|
curDate = curDate.addDays(1);
|
|
}
|
|
}
|
|
|
|
void CalPrintBase::drawAgendaDayBox(QPainter &p,
|
|
const QRect &box,
|
|
const QDate &date,
|
|
const KCalCore::Event::List &eventList,
|
|
const QTime &startTime,
|
|
const QTime &endTime,
|
|
const QList<QDate> &workDays) const
|
|
{
|
|
QTime myFromTime, myToTime;
|
|
if (startTime.isValid()) {
|
|
myFromTime = startTime;
|
|
} else {
|
|
myFromTime = QTime(0, 0, 0);
|
|
}
|
|
if (endTime.isValid()) {
|
|
myToTime = endTime;
|
|
} else {
|
|
myToTime = QTime(23, 59, 59);
|
|
}
|
|
|
|
if (!workDays.contains(date)) {
|
|
drawShadedBox(p, boxBorderWidth(), QColor(232, 232, 232), box);
|
|
} else {
|
|
drawBox(p, boxBorderWidth(), box);
|
|
}
|
|
|
|
const bool printConf = typeOptions().testFlag(
|
|
CalPrintBase::TypeConfidential); //TODO should be false by default
|
|
const bool printPrivate = typeOptions().testFlag(
|
|
CalPrintBase::TypePrivate); //TODO should be false by default
|
|
|
|
if (rangeOptions().testFlag(CalPrintBase::RangeTimeExpand)) {//TODO should be false by default
|
|
// Adapt start/end times to include complete events
|
|
Q_FOREACH (const KCalCore::Event::Ptr &event, eventList) {
|
|
Q_ASSERT(event);
|
|
if ((!printConf && event->secrecy() == KCalCore::Incidence::SecrecyConfidential) ||
|
|
(!printPrivate && event->secrecy() == KCalCore::Incidence::SecrecyPrivate)) {
|
|
continue;
|
|
}
|
|
// skip items without times so that we do not adjust for all day items
|
|
if (event->allDay()) {
|
|
continue;
|
|
}
|
|
if (event->dtStart().time() < myFromTime) {
|
|
myFromTime = event->dtStart().time();
|
|
}
|
|
if (event->dtEnd().time() > myToTime) {
|
|
myToTime = event->dtEnd().time();
|
|
}
|
|
}
|
|
}
|
|
|
|
// calculate the height of a cell and of a minute
|
|
int totalsecs = myFromTime.secsTo(myToTime);
|
|
float minlen = box.height() * 60. / totalsecs;
|
|
float cellHeight = 60. * minlen;
|
|
float currY = box.top();
|
|
|
|
// print grid:
|
|
QTime curTime(QTime(myFromTime.hour(), 0, 0));
|
|
currY += myFromTime.secsTo(curTime) * minlen / 60;
|
|
|
|
while (curTime < myToTime && curTime.isValid()) {
|
|
if (currY > box.top()) {
|
|
p.drawLine(box.left(), int(currY), box.right(), int(currY));
|
|
}
|
|
currY += cellHeight / 2;
|
|
if ((currY > box.top()) && (currY < box.bottom())) {
|
|
// enough space for half-hour line
|
|
QPen oldPen(p.pen());
|
|
p.setPen(QColor(192, 192, 192)); //TODO: define this color
|
|
p.drawLine(box.left(), int(currY), box.right(), int(currY));
|
|
|
|
p.setPen(oldPen);
|
|
}
|
|
if (curTime.secsTo(myToTime) > 3600) {
|
|
curTime = curTime.addSecs(3600);
|
|
} else {
|
|
curTime = myToTime;
|
|
}
|
|
currY += cellHeight / 2;
|
|
}
|
|
|
|
KDateTime startPrintDate = KDateTime(date, myFromTime);
|
|
KDateTime endPrintDate = KDateTime(date, myToTime);
|
|
|
|
// Calculate horizontal positions and widths of events taking into account
|
|
// overlapping events
|
|
|
|
QList<CellItem *> cells;
|
|
|
|
Q_FOREACH (const KCalCore::Event::Ptr &event, eventList) {
|
|
if (event->allDay()) {
|
|
continue;
|
|
}
|
|
QList<KDateTime>::ConstIterator it;
|
|
QList<KDateTime> times = event->startDateTimesForDate(date);
|
|
for (it = times.constBegin(); it != times.constEnd(); ++it) {
|
|
cells.append(new PrintCellItem(event, (*it), event->endDateForStart(*it)));
|
|
}
|
|
}
|
|
|
|
QListIterator<CellItem *> it1(cells);
|
|
while (it1.hasNext()) {
|
|
CellItem *placeItem = it1.next();
|
|
CellItem::placeItem(cells, placeItem);
|
|
|
|
}
|
|
|
|
QListIterator<CellItem *> it2(cells);
|
|
while (it2.hasNext()) {
|
|
PrintCellItem *placeItem = static_cast<PrintCellItem *>(it2.next());
|
|
drawAgendaItem(placeItem, p, startPrintDate, endPrintDate, minlen, box);
|
|
}
|
|
}
|
|
|
|
void CalPrintBase::drawAgendaItem(PrintCellItem *item, QPainter &p,
|
|
const KDateTime &startPrintDate,
|
|
const KDateTime &endPrintDate,
|
|
float minlen, const QRect &box) const
|
|
{
|
|
KCalCore::Event::Ptr event = item->event();
|
|
|
|
// start/end of print area for event
|
|
KDateTime startTime = item->start();
|
|
KDateTime endTime = item->end();
|
|
if ((startTime < endPrintDate && endTime > startPrintDate) ||
|
|
(endTime > startPrintDate && startTime < endPrintDate)) {
|
|
if (startTime < startPrintDate) {
|
|
startTime = startPrintDate;
|
|
}
|
|
if (endTime > endPrintDate) {
|
|
endTime = endPrintDate;
|
|
}
|
|
int currentWidth = box.width() / item->subCells();
|
|
int currentX = box.left() + item->subCell() * currentWidth;
|
|
int currentYPos =
|
|
int(box.top() + startPrintDate.secsTo(startTime) * minlen / 60.);
|
|
int currentHeight =
|
|
int(box.top() + startPrintDate.secsTo(endTime) * minlen / 60.) - currentYPos;
|
|
|
|
QRect eventBox(currentX, currentYPos, currentWidth, currentHeight);
|
|
QString str;
|
|
if (!infoOptions().testFlag(CalPrintBase::InfoTimeRange)) {
|
|
if (event->location().isEmpty()) {
|
|
str = cleanString(event->summary());
|
|
} else {
|
|
str = i18nc("summary, location", "%1, %2",
|
|
cleanString(event->summary()),
|
|
cleanString(event->location()));
|
|
}
|
|
} else {
|
|
if (event->location().isEmpty()) {
|
|
str = i18nc("starttime - endtime summary",
|
|
"%1-%2 %3",
|
|
KGlobal::locale()->formatTime(item->start().toLocalZone().time()),
|
|
KGlobal::locale()->formatTime(item->end().toLocalZone().time()),
|
|
cleanString(event->summary()));
|
|
} else {
|
|
str = i18nc("starttime - endtime summary, location",
|
|
"%1-%2 %3, %4",
|
|
KGlobal::locale()->formatTime(item->start().toLocalZone().time()),
|
|
KGlobal::locale()->formatTime(item->end().toLocalZone().time()),
|
|
cleanString(event->summary()),
|
|
cleanString(event->location()));
|
|
}
|
|
}
|
|
if (infoOptions().testFlag(CalPrintBase::InfoDescription) &&
|
|
!event->description().isEmpty()) {
|
|
str += '\n';
|
|
if (event->descriptionIsRich()) {
|
|
str += toPlainText(event->description());
|
|
} else {
|
|
str += event->description();
|
|
}
|
|
}
|
|
QFont oldFont(p.font());
|
|
//TODO: font option?
|
|
if (eventBox.height() < 24) {
|
|
if (eventBox.height() < 12) {
|
|
if (eventBox.height() < 8) {
|
|
p.setFont(QFont("sans-serif", 4));
|
|
} else {
|
|
p.setFont(QFont("sans-serif", 5));
|
|
}
|
|
} else {
|
|
p.setFont(QFont("sans-serif", 6));
|
|
}
|
|
} else {
|
|
p.setFont(QFont("sans-serif", 8));
|
|
}
|
|
drawItemBox(p, itemBoxBorderWidth(), eventBox, event, str);
|
|
p.setFont(oldFont);
|
|
}
|
|
}
|
|
|
|
void CalPrintBase::drawDaysOfWeekBox(QPainter &p, const QRect &box, const QDate &date) const
|
|
{
|
|
KCalendarSystem *calSys = calendarSystem();
|
|
drawSubHeader(p, box, (calSys) ? (calSys->weekDayName(date)) : QString());
|
|
}
|
|
|
|
void CalPrintBase::drawDaysOfWeek(QPainter &p, const QRect &box,
|
|
const QDate &fromDate, const QDate &toDate) const
|
|
{
|
|
double cellWidth = double(box.width()) / double(fromDate.daysTo(toDate) + 1);
|
|
QDate cellDate(fromDate);
|
|
QRect dateBox(box);
|
|
int i = 0;
|
|
|
|
while (cellDate <= toDate) {
|
|
dateBox.setLeft(box.left() + int(i * cellWidth));
|
|
dateBox.setRight(box.left() + int((i + 1) * cellWidth));
|
|
drawDaysOfWeekBox(p, dateBox, cellDate);
|
|
cellDate = cellDate.addDays(1);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
int CalPrintBase::drawAllDayBox(QPainter &p, const QRect &box,
|
|
const QDate &date, const KCalCore::Event::List &eventList,
|
|
bool expandAll) const
|
|
{
|
|
KCalCore::Event::List::Iterator it;
|
|
int offset = box.top();
|
|
QString multiDayStr;
|
|
|
|
KCalCore::Event::List evList = eventList;
|
|
KCalCore::Event::Ptr hd = holidayEvent(date);
|
|
if (hd) {
|
|
evList.prepend(hd);
|
|
}
|
|
|
|
const bool printConf = typeOptions().testFlag(
|
|
CalPrintBase::TypeConfidential); //TODO should be false by default
|
|
const bool printPrivate = typeOptions().testFlag(
|
|
CalPrintBase::TypePrivate); //TODO should be false by default
|
|
|
|
it = evList.begin();
|
|
while (it != evList.end()) {
|
|
KCalCore::Event::Ptr currEvent = *it;
|
|
if ((!printConf && currEvent->secrecy() == KCalCore::Incidence::SecrecyConfidential) ||
|
|
(!printPrivate && currEvent->secrecy() == KCalCore::Incidence::SecrecyPrivate)) {
|
|
continue;
|
|
}
|
|
if (currEvent && currEvent->allDay()) {
|
|
// set the colors according to the categories
|
|
if (expandAll) {
|
|
QRect eventBox(box);
|
|
eventBox.setTop(offset);
|
|
drawItemBox(p, itemBoxBorderWidth(), eventBox, currEvent, currEvent->summary());
|
|
offset += box.height();
|
|
} else {
|
|
if (!multiDayStr.isEmpty()) {
|
|
multiDayStr += ", ";
|
|
}
|
|
multiDayStr += currEvent->summary();
|
|
}
|
|
it = evList.erase(it);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
|
|
int ret = box.height();
|
|
QRect eventBox(box);
|
|
if (!expandAll) {
|
|
if (!multiDayStr.isEmpty()) {
|
|
drawShadedBox(p, boxBorderWidth(), QColor(180, 180, 180), eventBox);
|
|
drawItemString(p, eventBox, multiDayStr);
|
|
} else {
|
|
drawBox(p, boxBorderWidth(), eventBox);
|
|
}
|
|
} else {
|
|
ret = offset - box.top();
|
|
eventBox.setBottom(ret);
|
|
drawBox(p, boxBorderWidth(), eventBox);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void CalPrintBase::drawDayIncidence(QPainter &p, const QRect &dayBox,
|
|
const QString &time,
|
|
const QString &summary,
|
|
const QString &description,
|
|
int &textY,
|
|
bool richDescription) const
|
|
{
|
|
kDebug() << "summary =" << summary;
|
|
|
|
int flags = Qt::AlignLeft | Qt::OpaqueMode;
|
|
QFontMetrics fm = p.fontMetrics();
|
|
const int borderWidth = p.pen().width() + 1;
|
|
QRect timeBound = p.boundingRect(dayBox.x() + borderWidth,
|
|
dayBox.y() + textY,
|
|
dayBox.width(), fm.lineSpacing(),
|
|
flags, time);
|
|
|
|
int summaryWidth = time.isEmpty() ? 0 : timeBound.width() + 3;
|
|
QRect summaryBound = QRect(dayBox.x() + borderWidth + summaryWidth,
|
|
dayBox.y() + textY + 1,
|
|
dayBox.width() - summaryWidth - (borderWidth * 2),
|
|
dayBox.height() - textY);
|
|
|
|
QString summaryText = summary;
|
|
QString descText = toPlainText(description);
|
|
bool boxOverflow = false;
|
|
|
|
const bool includeDescription = infoOptions().testFlag(
|
|
CalPrintBase::InfoDescription); // TODO false by default
|
|
|
|
if (extraOptions().testFlag(CalPrintBase::ExtraSingleLine)) {//TODO should be true by default
|
|
if (includeDescription && !descText.isEmpty()) {
|
|
summaryText += ", " + descText;
|
|
}
|
|
int totalHeight = fm.lineSpacing() + borderWidth;
|
|
int textBoxHeight = (totalHeight > (dayBox.height() - textY)) ?
|
|
dayBox.height() - textY :
|
|
totalHeight;
|
|
summaryBound.setHeight(textBoxHeight);
|
|
QRect lineRect(dayBox.x() + borderWidth, dayBox.y() + textY,
|
|
dayBox.width() - (borderWidth * 2), textBoxHeight);
|
|
drawBox(p, 1, lineRect);
|
|
if (!time.isEmpty()) {
|
|
p.drawText(timeBound, flags, time);
|
|
}
|
|
p.drawText(summaryBound, flags, summaryText);
|
|
} else {
|
|
QTextDocument textDoc;
|
|
QTextCursor textCursor(&textDoc);
|
|
if (richDescription) {
|
|
QTextCursor textCursor(&textDoc);
|
|
textCursor.insertText(summaryText);
|
|
if (includeDescription && !description.isEmpty()) {
|
|
textCursor.insertText("\n");
|
|
textCursor.insertHtml(description);
|
|
}
|
|
} else {
|
|
textCursor.insertText(summaryText);
|
|
if (includeDescription && !descText.isEmpty()) {
|
|
textCursor.insertText("\n");
|
|
textCursor.insertText(descText);
|
|
}
|
|
}
|
|
textDoc.setPageSize(QSize(summaryBound.width(), summaryBound.height()));
|
|
p.save();
|
|
QRect clipBox(0, 0, summaryBound.width(), summaryBound.height());
|
|
p.setFont(p.font());
|
|
p.translate(summaryBound.x(), summaryBound.y());
|
|
summaryBound.setHeight(textDoc.documentLayout()->documentSize().height());
|
|
if (summaryBound.bottom() > dayBox.bottom()) {
|
|
summaryBound.setBottom(dayBox.bottom());
|
|
}
|
|
clipBox.setHeight(summaryBound.height());
|
|
p.restore();
|
|
|
|
p.save();
|
|
QRect backBox(timeBound.x(), timeBound.y(),
|
|
dayBox.width() - (borderWidth * 2), clipBox.height());
|
|
drawBox(p, 1, backBox);
|
|
|
|
if (!time.isEmpty()) {
|
|
if (timeBound.bottom() > dayBox.bottom()) {
|
|
timeBound.setBottom(dayBox.bottom());
|
|
}
|
|
timeBound.moveTop(timeBound.y() + (summaryBound.height() - timeBound.height()) / 2);
|
|
p.drawText(timeBound, flags, time);
|
|
}
|
|
p.translate(summaryBound.x(), summaryBound.y());
|
|
textDoc.drawContents(&p, clipBox);
|
|
p.restore();
|
|
boxOverflow = textDoc.pageCount() > 1;
|
|
}
|
|
if (summaryBound.bottom() < dayBox.bottom()) {
|
|
QPen oldPen(p.pen());
|
|
p.setPen(QPen());
|
|
p.drawLine(dayBox.x(), summaryBound.bottom(),
|
|
dayBox.x() + dayBox.width(), summaryBound.bottom());
|
|
p.setPen(oldPen);
|
|
}
|
|
textY += summaryBound.height();
|
|
|
|
// show that we have overflowed the box
|
|
if (boxOverflow) {
|
|
QPolygon poly(3);
|
|
int x = dayBox.x() + dayBox.width();
|
|
int y = dayBox.y() + dayBox.height();
|
|
poly.setPoint(0, x - 10, y);
|
|
poly.setPoint(1, x, y - 10);
|
|
poly.setPoint(2, x, y);
|
|
QBrush oldBrush(p.brush());
|
|
p.setBrush(QBrush(Qt::black));
|
|
p.drawPolygon(poly);
|
|
p.setBrush(oldBrush);
|
|
textY = dayBox.height();
|
|
}
|
|
}
|
|
|
|
void CalPrintBase::drawNoteLines(QPainter &p, const QRect &box, int startY) const
|
|
{
|
|
int lineHeight = int(p.fontMetrics().lineSpacing() * 1.5);
|
|
int linePos = box.y();
|
|
int startPos = startY;
|
|
// adjust line to start at multiple from top of box for alignment
|
|
while (linePos < startPos) {
|
|
linePos += lineHeight;
|
|
}
|
|
QPen oldPen(p.pen());
|
|
p.setPen(Qt::DotLine);
|
|
while (linePos < box.bottom()) {
|
|
p.drawLine(box.left() + padding(), linePos,
|
|
box.right() - padding(), linePos);
|
|
linePos += lineHeight;
|
|
}
|
|
p.setPen(oldPen);
|
|
}
|
|
|
|
void CalPrintBase::drawDayBox(QPainter &p,
|
|
const QRect &box,
|
|
const QDate &date,
|
|
const QTime &startTime, const QTime &endTime,
|
|
bool fullDate) const
|
|
{
|
|
QString dayNumStr;
|
|
const KLocale *local = KGlobal::locale();
|
|
|
|
QTime myStartTime, myEndTime;
|
|
if (startTime.isValid()) {
|
|
myStartTime = startTime;
|
|
} else {
|
|
myStartTime = QTime(0, 0, 0);
|
|
}
|
|
if (endTime.isValid()) {
|
|
myEndTime = endTime;
|
|
} else {
|
|
myEndTime = QTime(23, 59, 59);
|
|
}
|
|
|
|
if (fullDate && calendarSystem()) {
|
|
dayNumStr = i18nc("weekday, shortmonthname daynumber",
|
|
"%1, %2 <numid>%3</numid>",
|
|
calendarSystem()->weekDayName(date),
|
|
calendarSystem()->monthName(date, KCalendarSystem::ShortName),
|
|
date.day());
|
|
} else {
|
|
dayNumStr = QString::number(date.day());
|
|
}
|
|
|
|
QRect subHeaderBox(box);
|
|
subHeaderBox.setHeight(subHeaderHeight());
|
|
drawShadedBox(p, boxBorderWidth(), p.background(), box);
|
|
drawShadedBox(p, 0, QColor(232, 232, 232), subHeaderBox);
|
|
drawBox(p, boxBorderWidth(), box);
|
|
QString hstring(holidayString(date));
|
|
const QFont oldFont(p.font());
|
|
|
|
QRect headerTextBox(subHeaderBox);
|
|
headerTextBox.setLeft(subHeaderBox.left() + 5);
|
|
headerTextBox.setRight(subHeaderBox.right() - 5);
|
|
if (!hstring.isEmpty()) {
|
|
//TODO: option for this font
|
|
p.setFont(QFont("sans-serif", 8, QFont::Bold, true));
|
|
p.drawText(headerTextBox, Qt::AlignLeft | Qt::AlignVCenter, hstring);
|
|
}
|
|
//TODO: option for this font
|
|
p.setFont(QFont("sans-serif", 10, QFont::Bold));
|
|
p.drawText(headerTextBox, Qt::AlignRight | Qt::AlignVCenter, dayNumStr);
|
|
|
|
const KCalCore::Event::List eventList =
|
|
printCalendar()->events(date, KSystemTimeZones::local(),
|
|
KCalCore::EventSortStartDate,
|
|
KCalCore::SortDirectionAscending);
|
|
|
|
QString timeText;
|
|
//TODO: option for this font
|
|
p.setFont(QFont("sans-serif", 7));
|
|
|
|
const bool printConf = typeOptions().testFlag(
|
|
CalPrintBase::TypeConfidential); //TODO should be false by default
|
|
const bool printPrivate = typeOptions().testFlag(
|
|
CalPrintBase::TypePrivate); //TODO should be false by default
|
|
const bool printRecurDaily = rangeOptions().testFlag(
|
|
CalPrintBase::RangeRecurDaily); //TODO should be false by default?
|
|
const bool printRecurWeekly = rangeOptions().testFlag(
|
|
CalPrintBase::RangeRecurWeekly); //TODO should be false by defualt?
|
|
|
|
int textY = subHeaderHeight(); // gives the relative y-coord of the next printed entry
|
|
unsigned int visibleEventsCounter = 0;
|
|
Q_FOREACH (const KCalCore::Event::Ptr &currEvent, eventList) {
|
|
Q_ASSERT(currEvent);
|
|
if (!currEvent->allDay()) {
|
|
if (currEvent->dtEnd().toLocalZone().time() <= myStartTime ||
|
|
currEvent->dtStart().toLocalZone().time() > myEndTime) {
|
|
continue;
|
|
}
|
|
}
|
|
if ((!printRecurDaily && currEvent->recurrenceType() == KCalCore::Recurrence::rDaily) ||
|
|
(!printRecurWeekly && currEvent->recurrenceType() == KCalCore::Recurrence::rWeekly)) {
|
|
continue;
|
|
}
|
|
if ((!printConf && currEvent->secrecy() == KCalCore::Incidence::SecrecyConfidential) ||
|
|
(!printPrivate && currEvent->secrecy() == KCalCore::Incidence::SecrecyPrivate)) {
|
|
continue;
|
|
}
|
|
if (currEvent->allDay() || currEvent->isMultiDay()) {
|
|
timeText.clear();
|
|
} else {
|
|
timeText = local->formatTime(currEvent->dtStart().toLocalZone().time()) + ' ';
|
|
}
|
|
p.save();
|
|
setColorsByIncidenceCategory(p, currEvent);
|
|
QString summaryStr = currEvent->summary();
|
|
if (!currEvent->location().isEmpty()) {
|
|
summaryStr = i18nc("summary, location",
|
|
"%1, %2", summaryStr, currEvent->location());
|
|
}
|
|
drawDayIncidence(p, box, timeText,
|
|
summaryStr, currEvent->description(),
|
|
textY, currEvent->descriptionIsRich());
|
|
p.restore();
|
|
visibleEventsCounter++;
|
|
|
|
if (textY >= box.height()) {
|
|
const QChar downArrow(0x21e3);
|
|
|
|
const unsigned int invisibleIncidences =
|
|
(eventList.count() - visibleEventsCounter) + printCalendar()->todos(date).count();
|
|
if (invisibleIncidences > 0) {
|
|
const QString warningMsg =
|
|
QString("%1 (%2)").arg(downArrow).arg(invisibleIncidences);
|
|
|
|
QFontMetrics fm(p.font());
|
|
QRect msgRect = fm.boundingRect(warningMsg);
|
|
msgRect.setRect(box.right() - msgRect.width() - 2,
|
|
box.bottom() - msgRect.height() - 2,
|
|
msgRect.width(), msgRect.height());
|
|
|
|
p.save();
|
|
p.setPen(Qt::red); //krazy:exclude=qenums we don't allow custom print colors
|
|
p.drawText(msgRect, Qt::AlignLeft, warningMsg);
|
|
p.restore();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (textY < box.height()) {
|
|
KCalCore::Todo::List todoList = printCalendar()->todos(date);
|
|
Q_FOREACH (const KCalCore::Todo::Ptr &todo, todoList) {
|
|
if (!todo->allDay()) {
|
|
if ((todo->hasDueDate() && todo->dtDue().toLocalZone().time() <= myStartTime) ||
|
|
(todo->hasStartDate() && todo->dtStart().toLocalZone().time() > myEndTime)) {
|
|
continue;
|
|
}
|
|
}
|
|
if ((!printRecurDaily && todo->recurrenceType() == KCalCore::Recurrence::rDaily) ||
|
|
(!printRecurWeekly && todo->recurrenceType() == KCalCore::Recurrence::rWeekly)) {
|
|
continue;
|
|
}
|
|
if ((!printConf && todo->secrecy() == KCalCore::Incidence::SecrecyConfidential) ||
|
|
(!printPrivate && todo->secrecy() == KCalCore::Incidence::SecrecyPrivate)) {
|
|
continue;
|
|
}
|
|
if (todo->hasStartDate() && !todo->allDay()) {
|
|
timeText =
|
|
KGlobal::locale()->formatTime(todo->dtStart().toLocalZone().time()) + ' ';
|
|
} else {
|
|
timeText.clear();
|
|
}
|
|
p.save();
|
|
setColorsByIncidenceCategory(p, todo);
|
|
QString summaryStr = todo->summary();
|
|
if (!todo->location().isEmpty()) {
|
|
summaryStr = i18nc("summary, location",
|
|
"%1, %2", summaryStr, todo->location());
|
|
}
|
|
|
|
QString str;
|
|
if (todo->hasDueDate()) {
|
|
if (!todo->allDay()) {
|
|
str = i18nc("to-do summary (Due: datetime)", "%1 (Due: %2)",
|
|
summaryStr,
|
|
KGlobal::locale()->formatDateTime(todo->dtDue().toLocalZone()));
|
|
} else {
|
|
str = i18nc("to-do summary (Due: date)", "%1 (Due: %2)",
|
|
summaryStr,
|
|
KGlobal::locale()->formatDate(
|
|
todo->dtDue().toLocalZone().date(), KLocale::ShortDate));
|
|
}
|
|
} else {
|
|
str = summaryStr;
|
|
}
|
|
drawDayIncidence(p, box, timeText,
|
|
i18n("To-do: %1", str), todo->description(),
|
|
textY, todo->descriptionIsRich());
|
|
p.restore();
|
|
}
|
|
}
|
|
if (extraOptions().testFlag(CalPrintBase::ExtraNoteLines)) {//TODO should be false by default
|
|
drawNoteLines(p, box, box.y() + textY);
|
|
}
|
|
|
|
p.setFont(oldFont);
|
|
}
|
|
|
|
// Utility Functions that could be moved into CalendarSupport or somesuch
|
|
int CalPrintBase::weekdayColumn(const int weekday) const
|
|
{
|
|
int w = weekday + 7 - KGlobal::locale()->weekStartDay();
|
|
return w % 7;
|
|
}
|
|
|
|
QString CalPrintBase::cleanString(const QString &str) const
|
|
{
|
|
QString ret = str;
|
|
return ret.replace('\n', ' ');
|
|
}
|
|
|
|
QString CalPrintBase::toPlainText(const QString &htmlText) const
|
|
{
|
|
return QTextDocumentFragment::fromHtml(htmlText).toPlainText();
|
|
}
|
|
|
|
QColor CalPrintBase::getTextColor(const QColor &c) const
|
|
{
|
|
double luminance = (c.red() * 0.299) + (c.green() * 0.587) + (c.blue() * 0.114);
|
|
return (luminance > 128.0) ? QColor(0, 0, 0) : QColor(255, 255, 255);
|
|
}
|
|
|
|
QColor CalPrintBase::categoryColor(const QStringList &categories) const
|
|
{
|
|
if (categories.isEmpty()) {
|
|
return CalendarSupport::KCalPrefs::instance()->unsetCategoryColor();
|
|
}
|
|
// FIXME: Correctly treat events with multiple categories
|
|
const QString cat = categories.first();
|
|
QColor bgColor;
|
|
if (cat.isEmpty()) {
|
|
bgColor = CalendarSupport::KCalPrefs::instance()->unsetCategoryColor();
|
|
} else {
|
|
bgColor = CalendarSupport::KCalPrefs::instance()->categoryColor(cat);
|
|
}
|
|
return bgColor;
|
|
}
|
|
|
|
QColor CalPrintBase::categoryBgColor(const KCalCore::Incidence::Ptr &incidence) const
|
|
{
|
|
if (incidence) {
|
|
QColor backColor = categoryColor(incidence->categories());
|
|
if (incidence->type() == KCalCore::Incidence::TypeTodo) {
|
|
if ((incidence.staticCast<KCalCore::Todo>())->isOverdue()) {
|
|
//TODO make this available from CalendarSupport::KCalPrefs
|
|
backColor = QColor(255, 100, 100); //was KOPrefs::instance()->todoOverdueColor();
|
|
}
|
|
}
|
|
return backColor;
|
|
} else {
|
|
return QColor();
|
|
}
|
|
}
|
|
|
|
void CalPrintBase::setColorsByIncidenceCategory(QPainter &p,
|
|
const KCalCore::Incidence::Ptr &incidence) const
|
|
{
|
|
QColor bgColor = categoryBgColor(incidence);
|
|
if (bgColor.isValid()) {
|
|
p.setBrush(bgColor);
|
|
}
|
|
QColor tColor(getTextColor(bgColor));
|
|
if (tColor.isValid()) {
|
|
p.setPen(tColor);
|
|
}
|
|
}
|
|
|
|
QString CalPrintBase::holidayString(const QDate &date) const
|
|
{
|
|
QStringList lst = CalendarSupport::holiday(date);
|
|
return lst.join(i18nc("@item:intext delimiter for joining holiday names", ","));
|
|
}
|
|
|
|
KCalCore::Event::Ptr CalPrintBase::holidayEvent(const QDate &date) const
|
|
{
|
|
QString hstring(holidayString(date));
|
|
if (hstring.isEmpty()) {
|
|
return KCalCore::Event::Ptr();
|
|
}
|
|
|
|
KCalCore::Event::Ptr holiday(new KCalCore::Event);
|
|
holiday->setSummary(hstring);
|
|
holiday->setCategories(i18n("Holiday"));
|
|
|
|
KDateTime kdt(date, QTime(), KSystemTimeZones::local());
|
|
holiday->setDtStart(kdt);
|
|
holiday->setDtEnd(kdt);
|
|
holiday->setAllDay(true);
|
|
|
|
return holiday;
|
|
}
|