karm Library API Documentation

timekard.cpp

00001 /*
00002  *   This file only: 
00003  *     Copyright (C) 2003  Mark Bucciarelli <mark@hubcapconsutling.com>
00004  *
00005  *   This program is free software; you can redistribute it and/or modify
00006  *   it under the terms of the GNU General Public License as published by
00007  *   the Free Software Foundation; either version 2 of the License, or
00008  *   (at your option) any later version.
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details.
00014  *
00015  *   You should have received a copy of the GNU General Public License along
00016  *   with this program; if not, write to the 
00017  *      Free Software Foundation, Inc.
00018  *      59 Temple Place - Suite 330 
00019  *      Boston, MA  02111-1307  USA.
00020  *
00021  */
00022 
00023 // #include <iostream>
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>            // i18n
00033 #include <event.h>
00034 
00035 #include "karmutility.h"        // formatTime()
00036 #include "timekard.h"
00037 #include "task.h"
00038 #include "taskview.h"
00039 
00040 const int taskWidth = 40;
00041 const int timeWidth = 6; 
00042 const int totalTimeWidth = 7;
00043 const int reportWidth = taskWidth + timeWidth;
00044 const int weekReportWidth = taskWidth + (7 * timeWidth) + totalTimeWidth;
00045 
00046 const QString cr = QString::fromLatin1("\n");
00047 
00048 QString TimeKard::totalsAsText(TaskView* taskview, bool justThisTask)
00049 {
00050   QString retval;
00051   QString taskhdr, totalhdr;
00052   QString line;
00053   QString buf;
00054   long sum;
00055 
00056   line.fill('-', reportWidth);
00057   line += cr;
00058 
00059   // header
00060   retval += i18n("Task Totals") + cr;
00061   retval += KGlobal::locale()->formatDateTime(QDateTime::currentDateTime());
00062   retval += cr + cr;
00063   retval += QString(QString::fromLatin1("%1    %2"))
00064     .arg(i18n("Time"), timeWidth)
00065     .arg(i18n("Task"));
00066   retval += cr;
00067   retval += line;
00068 
00069   // tasks
00070   if (taskview->current_item())
00071   {
00072     if (justThisTask)
00073     {
00074       // a task's total time includes the sum of all subtask times
00075       sum = taskview->current_item()->totalTime();
00076       printTask(taskview->current_item(), retval, 0);
00077     }
00078     else
00079     {
00080       sum = 0;
00081       for (Task* task= taskview->current_item(); task;
00082           task= task->nextSibling())
00083       {
00084         sum += task->totalTime();
00085         printTask(task, retval, 0);
00086       }
00087     } 
00088 
00089     // total
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 void TimeKard::printTask(Task *task, QString &s, int level)
00103 {
00104   QString buf;
00105 
00106   s += buf.fill(' ', level);
00107   s += QString(QString::fromLatin1("%1    %2"))
00108     .arg(formatTime(task->totalTime()), timeWidth)
00109     .arg(task->name());
00110   s += cr;
00111 
00112   for (Task* subTask = task->firstChild();
00113       subTask;
00114       subTask = subTask->nextSibling())
00115   {
00116     printTask(subTask, s, level+1);
00117   }
00118 }
00119 
00120 void TimeKard::printWeekTask(const Task *task, 
00121     const QMap<QString,long>& taskdaytotals, 
00122     QMap<QString,long>& daytotals, 
00123     const Week& week, const int level, QString& s)
00124 {
00125   QString buf;
00126   QString daytaskkey, daykey;
00127   QDate day;
00128   long weeksum;
00129 
00130   day = week.start();
00131   weeksum = 0;
00132   for (int i = 0; i < 7; i++)
00133   {
00134     daykey = day.toString(QString::fromLatin1("yyyyMMdd"));
00135     daytaskkey = QString::fromLatin1("%1_%2")
00136       .arg(daykey)
00137       .arg(task->uid());
00138 
00139     if (taskdaytotals.contains(daytaskkey))
00140     {
00141       s += QString::fromLatin1("%1")
00142         .arg(formatTime(taskdaytotals[daytaskkey]/60), timeWidth);
00143       weeksum += taskdaytotals[daytaskkey];  // in seconds
00144       
00145       if (daytotals.contains(daykey))
00146         daytotals.replace(daykey, daytotals[daykey] + taskdaytotals[daytaskkey]);
00147       else
00148         daytotals.insert(daykey, taskdaytotals[daytaskkey]);
00149     }
00150     else
00151     {
00152       buf.fill(' ', timeWidth);
00153       s += buf;
00154     }
00155 
00156     day = day.addDays(1);
00157   }
00158 
00159   // Total for task this week
00160   s += QString::fromLatin1("%1").arg(formatTime(weeksum/60), totalTimeWidth);
00161 
00162   // Task name
00163   s += buf.fill(' ', level + 1);
00164   s += QString::fromLatin1("%1").arg(task->name());
00165   s += cr;
00166 
00167   for (Task* subTask = task->firstChild();
00168       subTask;
00169       subTask = subTask->nextSibling())
00170   {
00171     printWeekTask(subTask, taskdaytotals, daytotals, week, level+1, s);
00172   }
00173 }
00174 
00175 QString TimeKard::historyAsText(TaskView* taskview, const QDate& from,
00176     const QDate& to, bool justThisTask)
00177 {
00178   QString retval;
00179   QString taskhdr, totalhdr;
00180   QString line, buf;
00181   long sum;
00182   
00183   QValueList<Week>::iterator week;
00184   QValueList<HistoryEvent> events;
00185   QValueList<HistoryEvent>::iterator event;
00186   QMap<QString, long> taskdaytotals;
00187   QMap<QString, long> daytotals;
00188   QString daytaskkey, daykey;
00189   QDate day;
00190 
00191   line.fill('-', weekReportWidth);
00192   line += cr;
00193 
00194   // header
00195   retval += i18n("Task History") + cr;
00196   retval += i18n("From %1 to %2")
00197     .arg(KGlobal::locale()->formatDate(from))
00198     .arg(KGlobal::locale()->formatDate(to));
00199   retval += cr;
00200   retval += i18n("Printed on: %1")
00201     .arg(KGlobal::locale()->formatDateTime(QDateTime::currentDateTime()));
00202 
00203   // output one time card table for each week in the date range
00204   QValueList<Week> weeks = Week::weeksFromDateRange(from, to);
00205   for (week = weeks.begin(); week != weeks.end(); ++week)
00206   {
00207     if ( (*week).start() < from && (*week).end() > to)
00208     {
00209       events = taskview->getHistory(from, to);
00210     }
00211     else if ( (*week).start() < from )
00212     {
00213       events = taskview->getHistory(from, (*week).end());
00214     }
00215     else if ( (*week).end() > to)
00216     {
00217       events = taskview->getHistory((*week).start(), to);
00218     }
00219     else
00220     {
00221       events = taskview->getHistory((*week).start(), (*week).end());
00222     }
00223 
00224     taskdaytotals.clear();
00225     daytotals.clear();
00226 
00227     // Build lookup dictionary used to output data in table cells.  keys are
00228     // in this format: YYYYMMDD_NNNNNN, where Y = year, M = month, d = day and
00229     // NNNNN = the VTODO uid.  The value is the total seconds logged against
00230     // that task on that day.  Note the UID is the todo id, not the event id,
00231     // so times are accumulated for each task.
00232     for (event = events.begin(); event != events.end(); ++event)
00233     {
00234       daykey = (*event).start().date().toString(QString::fromLatin1("yyyyMMdd"));
00235       daytaskkey = QString(QString::fromLatin1("%1_%2"))
00236         .arg(daykey)
00237         .arg((*event).todoUid());
00238 
00239       if (taskdaytotals.contains(daytaskkey))
00240         taskdaytotals.replace(daytaskkey, 
00241             taskdaytotals[daytaskkey] + (*event).duration());
00242       else
00243         taskdaytotals.insert(daytaskkey, (*event).duration());
00244     }
00245 
00246     // week name
00247     retval += cr + cr;
00248     buf.fill(' ', int((weekReportWidth - (*week).name().length()) / 2));
00249     retval += buf + (*week).name() + cr;
00250 
00251     // day headings
00252     for (int i = 0; i < 7; i++)
00253     {
00254       retval += QString::fromLatin1("%1")
00255           .arg((*week).start().addDays(i).day(), timeWidth);
00256     }
00257     retval += cr;
00258     retval += line;
00259 
00260     // the tasks
00261     if (events.empty())
00262     {
00263       retval += i18n("  No hours logged.");
00264     }
00265     else
00266     {
00267       sum = 0;
00268       if (justThisTask)
00269       {
00270         printWeekTask(taskview->current_item(), taskdaytotals, daytotals, 
00271             (*week), 0, retval);
00272       }
00273       else
00274       {
00275         for (Task* task= taskview->current_item(); task;
00276             task= task->nextSibling())
00277         {
00278           printWeekTask(task, taskdaytotals, daytotals, (*week), 0, retval);
00279         }
00280       } 
00281       retval += line;
00282 
00283       // totals
00284       sum = 0;
00285       day = (*week).start();
00286       for (int i = 0; i < 7; i++)
00287       {
00288         daykey = day.toString(QString::fromLatin1("yyyyMMdd"));
00289 
00290         if (daytotals.contains(daykey))
00291         {
00292           retval += QString::fromLatin1("%1")
00293               .arg(formatTime(daytotals[daykey]/60), timeWidth);
00294           sum += daytotals[daykey];  // in seconds
00295         }
00296         else
00297         {
00298           buf.fill(' ', timeWidth);
00299           retval += buf;
00300         }
00301 
00302         day = day.addDays(1);
00303       }
00304 
00305       retval += QString::fromLatin1("%1 %2")
00306         .arg(formatTime(sum/60), totalTimeWidth)
00307         .arg(i18n("Total"));
00308     }
00309   }
00310   return retval;
00311 }
00312 
00313 Week::Week() {}
00314 
00315 Week::Week(QDate from)
00316 {
00317   _start = from;
00318 }
00319 
00320 QDate Week::start() const 
00321 { 
00322   return _start;
00323 }
00324 
00325 QDate Week::end() const
00326 {
00327   return _start.addDays(7);
00328 }
00329 
00330 QString Week::name() const
00331 {
00332   return QString(i18n("Week of %1"))
00333     .arg(KGlobal::locale()->formatDate(start()));
00334 }
00335 
00336 QValueList<Week> Week::weeksFromDateRange(const QDate& from, const QDate& to)
00337 {
00338   QDate start;
00339   QValueList<Week> weeks;
00340 
00341   // The QDate weekNumber() method always puts monday as the first day of the
00342   // week.  
00343   //
00344   // Not that it matters here, but week 1 always includes the first Thursday
00345   // of the year.  For example, January 1, 2000 was a Saturday, so
00346   // QDate(2000,1,1).weekNumber() returns 52.  
00347 
00348   // Since report always shows a full week, we generate a full week of dates,
00349   // even if from and to are the same date.  The week starts on the day
00350   // that is set in the locale settings.
00351   start = from.addDays( 
00352       -((7 - KGlobal::locale()->weekStartDay() + from.dayOfWeek()) % 7));
00353 
00354   for (QDate d = start; d <= to; d = d.addDays(7))
00355     weeks.append(Week(d));
00356 
00357   return weeks;
00358 }
00359 
KDE Logo
This file is part of the documentation for karm Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat May 1 11:37:53 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003