00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <qdatetime.h>
00026 #include <qpaintdevicemetrics.h>
00027 #include <qpainter.h>
00028 #include <qmap.h>
00029
00030 #include <kglobal.h>
00031 #include <kdebug.h>
00032 #include <klocale.h>
00033 #include <event.h>
00034
00035 #include "karmutility.h"
00036 #include "timekard.h"
00037 #include "task.h"
00038 #include "taskview.h"
00039 #include <assert.h>
00040
00041 const int taskWidth = 40;
00042 const int timeWidth = 6;
00043 const int totalTimeWidth = 7;
00044 const int reportWidth = taskWidth + timeWidth;
00045
00046 const QString cr = QString::fromLatin1("\n");
00047
00048 QString TimeKard::totalsAsText(TaskView* taskview, bool justThisTask)
00049 {
00050 QString retval;
00051 QString line;
00052 QString buf;
00053 long sum;
00054
00055 line.fill('-', reportWidth);
00056 line += cr;
00057
00058
00059 retval += i18n("Task Totals") + cr;
00060 retval += KGlobal::locale()->formatDateTime(QDateTime::currentDateTime());
00061 retval += cr + cr;
00062 retval += QString(QString::fromLatin1("%1 %2"))
00063 .arg(i18n("Time"), timeWidth)
00064 .arg(i18n("Task"));
00065 retval += cr;
00066 retval += line;
00067
00068
00069 if (taskview->current_item())
00070 {
00071 if (justThisTask)
00072 {
00073
00074 sum = taskview->current_item()->totalTime();
00075 printTask(taskview->current_item(), retval, 0);
00076 }
00077 else
00078 {
00079 sum = 0;
00080 for (Task* task= taskview->current_item(); task;
00081 task= task->nextSibling())
00082 {
00083 sum += task->totalTime();
00084 if ( task->totalTime() )
00085 printTask(task, retval, 0);
00086 }
00087 }
00088
00089
00090 buf.fill('-', reportWidth);
00091 retval += QString(QString::fromLatin1("%1")).arg(buf, timeWidth) + cr;
00092 retval += QString(QString::fromLatin1("%1 %2"))
00093 .arg(formatTime(sum),timeWidth)
00094 .arg(i18n("Total"));
00095 }
00096 else
00097 retval += i18n("No tasks.");
00098
00099 return retval;
00100 }
00101
00102
00103 void TimeKard::printTask(Task *task, QString &s, int level)
00104 {
00105 QString buf;
00106
00107 s += buf.fill(' ', level);
00108 s += QString(QString::fromLatin1("%1 %2"))
00109 .arg(formatTime(task->totalTime()), timeWidth)
00110 .arg(task->name());
00111 s += cr;
00112
00113 for (Task* subTask = task->firstChild();
00114 subTask;
00115 subTask = subTask->nextSibling())
00116 {
00117 if ( subTask->totalTime() )
00118 printTask(subTask, s, level+1);
00119 }
00120 }
00121
00122 void TimeKard::printTaskHistory(const Task *task,
00123 const QMap<QString,long>& taskdaytotals,
00124 QMap<QString,long>& daytotals,
00125 const QDate& from,
00126 const QDate& to,
00127 const int level, QString& s, bool totalsOnly)
00128 {
00129 long sectionsum = 0;
00130 for ( QDate day = from; day <= to; day = day.addDays(1) )
00131 {
00132 QString daykey = day.toString(QString::fromLatin1("yyyyMMdd"));
00133 QString daytaskkey = QString::fromLatin1("%1_%2")
00134 .arg(daykey)
00135 .arg(task->uid());
00136
00137 if (taskdaytotals.contains(daytaskkey))
00138 {
00139 if ( !totalsOnly )
00140 {
00141 s += QString::fromLatin1("%1")
00142 .arg(formatTime(taskdaytotals[daytaskkey]/60), timeWidth);
00143 }
00144 sectionsum += taskdaytotals[daytaskkey];
00145
00146 if (daytotals.contains(daykey))
00147 daytotals.replace(daykey, daytotals[daykey] + taskdaytotals[daytaskkey]);
00148 else
00149 daytotals.insert(daykey, taskdaytotals[daytaskkey]);
00150 }
00151 else if ( !totalsOnly )
00152 {
00153 QString buf;
00154 buf.fill(' ', timeWidth);
00155 s += buf;
00156 }
00157 }
00158
00159
00160 s += QString::fromLatin1("%1").arg(formatTime(sectionsum/60), totalTimeWidth);
00161
00162
00163 QString buf;
00164 s += buf.fill(' ', level + 1);
00165 s += QString::fromLatin1("%1").arg(task->name());
00166 s += cr;
00167
00168 for (Task* subTask = task->firstChild();
00169 subTask;
00170 subTask = subTask->nextSibling())
00171 {
00172
00173 printTaskHistory(subTask, taskdaytotals, daytotals, from, to, level+1, s, totalsOnly);
00174 }
00175 }
00176
00177 QString TimeKard::sectionHistoryAsText(
00178 TaskView* taskview,
00179 const QDate& sectionFrom, const QDate& sectionTo,
00180 const QDate& from, const QDate& to,
00181 const QString& name,
00182 bool justThisTask, bool totalsOnly)
00183 {
00184
00185 const int sectionReportWidth = taskWidth + ( totalsOnly ? 0 : sectionFrom.daysTo(sectionTo) * timeWidth ) + totalTimeWidth;
00186 assert( sectionReportWidth > 0 );
00187 QString line;
00188 line.fill('-', sectionReportWidth);
00189 line += cr;
00190
00191 QValueList<HistoryEvent> events;
00192 if ( sectionFrom < from && sectionTo > to)
00193 {
00194 events = taskview->getHistory(from, to);
00195 }
00196 else if ( sectionFrom < from )
00197 {
00198 events = taskview->getHistory(from, sectionTo);
00199 }
00200 else if ( sectionTo > to)
00201 {
00202 events = taskview->getHistory(sectionFrom, to);
00203 }
00204 else
00205 {
00206 events = taskview->getHistory(sectionFrom, sectionTo);
00207 }
00208
00209 QMap<QString, long> taskdaytotals;
00210 QMap<QString, long> daytotals;
00211
00212
00213
00214
00215
00216
00217 for (QValueList<HistoryEvent>::iterator event = events.begin(); event != events.end(); ++event)
00218 {
00219 QString daykey = (*event).start().date().toString(QString::fromLatin1("yyyyMMdd"));
00220 QString daytaskkey = QString::fromLatin1("%1_%2")
00221 .arg(daykey)
00222 .arg((*event).todoUid());
00223
00224 if (taskdaytotals.contains(daytaskkey))
00225 taskdaytotals.replace(daytaskkey,
00226 taskdaytotals[daytaskkey] + (*event).duration());
00227 else
00228 taskdaytotals.insert(daytaskkey, (*event).duration());
00229 }
00230
00231 QString retval;
00232
00233 retval += cr + cr;
00234 QString buf;
00235 if ( name.length() < (unsigned int)sectionReportWidth )
00236 buf.fill(' ', int((sectionReportWidth - name.length()) / 2));
00237 retval += buf + name + cr;
00238
00239 if ( !totalsOnly )
00240 {
00241
00242 for (QDate day = sectionFrom; day <= sectionTo; day = day.addDays(1))
00243 {
00244 retval += QString::fromLatin1("%1").arg(day.day(), timeWidth);
00245 }
00246 retval += cr;
00247 retval += line;
00248 }
00249
00250
00251 if (events.empty())
00252 {
00253 retval += " ";
00254 retval += i18n("No hours logged.");
00255 }
00256 else
00257 {
00258 if (justThisTask)
00259 {
00260 printTaskHistory(taskview->current_item(), taskdaytotals, daytotals,
00261 sectionFrom, sectionTo, 0, retval, totalsOnly);
00262 }
00263 else
00264 {
00265 for (Task* task= taskview->current_item(); task;
00266 task= task->nextSibling())
00267 {
00268 printTaskHistory(task, taskdaytotals, daytotals,
00269 sectionFrom, sectionTo, 0, retval, totalsOnly);
00270 }
00271 }
00272 retval += line;
00273
00274
00275 long sum = 0;
00276 for (QDate day = sectionFrom; day <= sectionTo; day = day.addDays(1))
00277 {
00278 QString daykey = day.toString(QString::fromLatin1("yyyyMMdd"));
00279
00280 if (daytotals.contains(daykey))
00281 {
00282 if ( !totalsOnly )
00283 {
00284 retval += QString::fromLatin1("%1")
00285 .arg(formatTime(daytotals[daykey]/60), timeWidth);
00286 }
00287 sum += daytotals[daykey];
00288 }
00289 else if ( !totalsOnly )
00290 {
00291 buf.fill(' ', timeWidth);
00292 retval += buf;
00293 }
00294 }
00295
00296 retval += QString::fromLatin1("%1 %2")
00297 .arg(formatTime(sum/60), totalTimeWidth)
00298 .arg(i18n("Total"));
00299 }
00300 return retval;
00301 }
00302
00303 QString TimeKard::historyAsText(TaskView* taskview, const QDate& from,
00304 const QDate& to, bool justThisTask, bool perWeek, bool totalsOnly)
00305 {
00306
00307 QString retval;
00308 retval += totalsOnly ? i18n("Task Totals") : i18n("Task History");
00309 retval += cr;
00310 retval += i18n("From %1 to %2")
00311 .arg(KGlobal::locale()->formatDate(from))
00312 .arg(KGlobal::locale()->formatDate(to));
00313 retval += cr;
00314 retval += i18n("Printed on: %1")
00315 .arg(KGlobal::locale()->formatDateTime(QDateTime::currentDateTime()));
00316
00317 if ( perWeek )
00318 {
00319
00320 QValueList<Week> weeks = Week::weeksFromDateRange(from, to);
00321 for (QValueList<Week>::iterator week = weeks.begin(); week != weeks.end(); ++week)
00322 {
00323 retval += sectionHistoryAsText( taskview, (*week).start(), (*week).end(), from, to, (*week).name(), justThisTask, totalsOnly );
00324 }
00325 } else
00326 {
00327 retval += sectionHistoryAsText( taskview, from, to, from, to, "", justThisTask, totalsOnly );
00328 }
00329 return retval;
00330 }
00331
00332 Week::Week() {}
00333
00334 Week::Week(QDate from)
00335 {
00336 _start = from;
00337 }
00338
00339 QDate Week::start() const
00340 {
00341 return _start;
00342 }
00343
00344 QDate Week::end() const
00345 {
00346 return _start.addDays(6);
00347 }
00348
00349 QString Week::name() const
00350 {
00351 return i18n("Week of %1").arg(KGlobal::locale()->formatDate(start()));
00352 }
00353
00354 QValueList<Week> Week::weeksFromDateRange(const QDate& from, const QDate& to)
00355 {
00356 QDate start;
00357 QValueList<Week> weeks;
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 start = from.addDays(
00370 -((7 - KGlobal::locale()->weekStartDay() + from.dayOfWeek()) % 7));
00371
00372 for (QDate d = start; d <= to; d = d.addDays(7))
00373 weeks.append(Week(d));
00374
00375 return weeks;
00376 }
00377