Commit d0817aae authored by Tomas Pospisek's avatar Tomas Pospisek
Browse files

* reengineered:

  * moved things to where they should be: class Task is now concerned with everything regarding a task
  * split DesktopTracker out of TaskView
  * each Task now has its own time instead of a cumulated one
* cleaned up headers/includes
* killed many bugs and introduced new interesting bugs
* comments to tasks can be logged (log: "nice chatting with customer")
* "Reset Session Times" is now "Start New Session" - thanks David Faure
* other things that I forgot

svn path=/trunk/kdepim/; revision=228686
parent 7906b0f5
BUGS
----
please report bugs to Tomas Pospisek <tpo_deb@sourcepole.ch> or at http://bugs.kde.org.
KArm 1.3
--------
- reengineering
- each task now has its own time
- tracking of desktops
- better logging
- comments can be added to log
- active task indication in the system tray
- "Reset Session Times" re-reversed and renamed to
"Start New Session" for clarity
- fixed a few bugs
- times are now saved in iCal format
KArm 1.2
--------
......
......@@ -8,14 +8,18 @@ SUBDIRS = support pics
METASOURCES = AUTO
karm_SOURCES = addtaskdialog.cpp main.cpp \
task.cpp mainwindow.cpp kaccelmenuwatch.cpp print.cpp \
preferences.cpp ktimewidget.cpp taskview.cpp idletimedetector.cpp logging.cpp karmutility.cpp tray.cpp
karm_SOURCES = desktoptracker.cpp edittaskdialog.cpp idletimedetector.cpp \
kaccelmenuwatch.cpp karmutility.cpp ktimewidget.cpp \
logging.cpp main.cpp \
mainwindow.cpp preferences.cpp print.cpp task.cpp \
taskview.cpp tray.cpp
karm_LDADD = -lkdeprint $(top_builddir)/libkcal/libkcal.la $(LIBXSS)
karm_LDFLAGS = $(all_libraries)
noinst_HEADERS = addtaskdialog.h taskview.h task.h toolicons.h mainwindow.h kaccelmenuwatch.h \
version.h print.h idletimedetector.h preferences.h ktimewidget.h logging.h karmutility.h \
tray.h
noinst_HEADERS = desktoptracker.h edittaskdialog.h \
idletimedetector.h kaccelmenuwatch.h \
karmutility.h ktimewidget.h logging.h mainwindow.h \
preferences.h print.h task.h taskview.h toolicons.h \
tray.h version.h
KDE_ICON = karm
......
$Id$
* times can be negative - does that make any sense?
* one can adjust subtask *and* task times which has the effect that times
won't add up any more - does that make sense?
* add notes to logentries
* the BUGS file contains nonsense
* check: times can be negative - does that make any sense?
* add better screenshot to http://pim.kde.org/components/karm.php
* KarmWindow::makeMenus -> export KAction?
* KarmWindow::contextMenuRequest QPopupMenu should be static!
* connect( ..contextMenu einordnen
* put connect( ..contextMenu at the right place
* mainwindow: move tray signals into tray.cpp
* formatTime has nothing to do in TaskView?
* "#ifndef header"s are inconsistent
* mainwindow.cpp: before loading view, check whether the file exists
and if not, create a blank one and ask wheter we want to add a task.
* add mouse double-click action (start new timer, stop old) to "Configure
Shortcuts" dialog.
* Deleting a task should be logged as well.
* deleting a task should be logged as well.
* log start/stop session
* Willi:
--------
* If one starts karm and installs some desktop tracking tasks nothing
happens. One has to restart karm in order to have them work.
* The tracker functionality should be split out into a separate file/class.
mainwindow.cpp is IMHO long enough as is.
* Willi / desktop tracker:
--------------------------
* Willi said he'd push:
......@@ -37,4 +27,16 @@ $Id$
* The runtime warnings still need to be fixed.
* app is crashing when leaving through the "x" on the upper right in the window.
* the desktop tracker is not able to handle a changing number of
desktops (i.e. if we add or remove a desktop)
Wishlist:
---------
* a default task that would start as soon as we've launched karm
* activeTasks should be cleaned up
* if two timers are active, associate a percentage with them, optimaly the
percentage should be configurable
* completed % per task
* don't display competed tasks
* context menu in headers for choosing if one wants to see some column or not
#ifndef KARM_DESKTOP_LIST_H
#define KARM_DESKTOP_LIST_H
#include <vector>
typedef std::vector<int> DesktopList;
#endif // KARM_DESKTOP_LIST_H
#include <algorithm> // std::find
#include "desktoptracker.h"
DesktopTracker::DesktopTracker ()
{
// Setup desktop change handling
connect( &kWinModule, SIGNAL( currentDesktopChanged(int) ),
this, SLOT( handleDesktopChange(int) ));
_desktopCount = kWinModule.numberOfDesktops();
_previousDesktop = kWinModule.currentDesktop()-1;
// TODO: removed? fixed by Lubos?
// currentDesktop will return 0 if no window manager is started
if( _previousDesktop < 0 ) _previousDesktop = 0;
}
void DesktopTracker::handleDesktopChange(int desktop)
{
desktop--; // desktopTracker starts with 0 for desktop 1
// notify start all tasks setup for running on desktop
TaskVector::iterator it;
// stop trackers for _previousDesktop
TaskVector tv = desktopTracker[_previousDesktop];
for (it = tv.begin(); it != tv.end(); it++) {
emit leftActiveDesktop(*it);
}
// start trackers for desktop
tv = desktopTracker[desktop];
for (it = tv.begin(); it != tv.end(); it++) {
emit reachedtActiveDesktop(*it);
}
_previousDesktop = desktop;
// emit updateButtons();
}
void DesktopTracker::startTracking()
{
int currentDesktop = kWinModule.currentDesktop() -1;
// TODO: removed? fixed by Lubos?
// currentDesktop will return 0 if no window manager is started
if ( currentDesktop < 0 ) currentDesktop = 0;
TaskVector &tv = desktopTracker[ currentDesktop ];
TaskVector::iterator tit = tv.begin();
while(tit!=tv.end()) {
emit reachedtActiveDesktop(*tit);
tit++;
}
}
void DesktopTracker::registerForDesktops( Task* task, DesktopList desktopList)
{
// if no desktop is marked, disable auto tracking for this task
if (desktopList.size()==0) {
for (int i=0; i<16; i++) {
TaskVector *v = &(desktopTracker[i]);
TaskVector::iterator tit = std::find(v->begin(), v->end(), task);
if (tit != v->end())
desktopTracker[i].erase(tit);
// if the task was priviously tracking this desktop then
// emit a signal that is not tracking it any more
if( i == kWinModule.currentDesktop() -1)
emit leftActiveDesktop(task);
}
return;
}
// If desktop contains entries then configure desktopTracker
// If a desktop was disabled, it will not be stopped automatically.
// If enabled: Start it now.
if (desktopList.size()>0) {
for (int i=0; i<16; i++) {
TaskVector& v = desktopTracker[i];
TaskVector::iterator tit = std::find(v.begin(), v.end(), task);
// Is desktop i in the desktop list?
if ( std::find( desktopList.begin(), desktopList.end(), i)
!= desktopList.end()) {
if (tit == v.end()) // not yet in start vector
v.push_back(task); // track in desk i
}
else { // delete it
if (tit != v.end()) // not in start vector any more
{
v.erase(tit); // so we delete it from desktopTracker
// if the task was priviously tracking this desktop then
// emit a signal that is not tracking it any more
if( i == kWinModule.currentDesktop() -1)
emit leftActiveDesktop(task);
}
}
}
startTracking();
}
}
void DesktopTracker::printTrackers() {
TaskVector::iterator it;
for (int i=0; i<16; i++) {
TaskVector& start = desktopTracker[i];
it = start.begin();
while (it != start.end()) {
it++;
}
}
}
#include "desktoptracker.moc"
#ifndef KARM_DESKTOP_TRACKER_H
#define KARM_DESKTOP_TRACKER_H
#include <vector>
#include <kwinmodule.h>
#include "desktoplist.h"
class Task;
typedef std::vector<Task *> TaskVector;
/** A utility to associate tasks with desktops
* As soon as a desktop is activated/left - an signal is emited for
* each task tracking that all tasks that want to track that desktop
*/
class DesktopTracker: public QObject
{
Q_OBJECT
public:
DesktopTracker();
void printTrackers();
void startTracking();
void registerForDesktops( Task* task, DesktopList dl );
int desktopCount() const { return _desktopCount; };
private: // member variables
KWinModule kWinModule;
// define vectors for at most 16 virtual desktops
// E.g.: desktopTrackerStop[3] contains a vector with
// all tasks to be notified, when switching to/from desk 3.
TaskVector desktopTracker[16];
int _previousDesktop;
int _desktopCount;
signals:
void reachedtActiveDesktop( Task* task );
void leftActiveDesktop( Task* task );
public slots:
void handleDesktopChange( int desktop );
};
#endif // KARM_DESKTOP_TRACKER_H
......@@ -5,7 +5,7 @@
#include <qtimer.h>
#include <kglobal.h>
#include <klocale.h>
#include <klocale.h> // i18n
IdleTimeDetector::IdleTimeDetector(int maxIdle)
{
......
#ifndef __IDLETIMER
#define __IDLETIMER
#ifndef KARM_IDLE_TIME_DETECTOR_H
#define KARM_IDLE_TIME_DETECTOR_H
#include <qobject.h>
#include "config.h"
#include "config.h" // HAVE_LIBXSS
class QTimer;
......@@ -96,4 +97,4 @@ private:
QTimer *_timer;
};
#endif // __IDLETIMER
#endif // KARM_IDLE_TIME_DETECTOR_H
......@@ -6,6 +6,8 @@
*/
#include <assert.h>
#include <qpopupmenu.h>
#include "kaccelmenuwatch.h"
KAccelMenuWatch::KAccelMenuWatch( KAccel *accel, QObject *parent )
......
......@@ -2,15 +2,16 @@
* kaccelmenuwatch.h -- Declaration of class KAccelMenuWatch.
* Generated by newclass on Thu Jan 7 15:05:26 EST 1999.
*/
#ifndef SSK_KACCELMENUWATCH_H
#define SSK_KACCELMENUWATCH_H
#ifndef KARM_K_ACCEL_MENU_WATCH_H
#define KARM_K_ACCEL_MENU_WATCH_H
#include <qobject.h>
#include <qpopupmenu.h>
#include <qptrlist.h>
#include <kaccel.h>
class QPopupMenu;
/**
* Easy updating of menu accels when changing a KAccel object.
*
......@@ -110,4 +111,4 @@ class KAccelMenuWatch : public QObject
KAccelMenuWatch( const KAccelMenuWatch& );
};
#endif // SSK_KACCELMENUWATCH_H
#endif // KARM_K_ACCEL_MENU_WATCH_H
......@@ -2,7 +2,7 @@
<MenuBar>
<Menu name="file" >
<text>&amp;File</text>
<Action name="reset_session_time" />
<Action name="start_new_session" />
<Action name="reset_all_times" />
</Menu>
<Menu name="clock" >
......
#include "task.h"
#ifndef KARM_UTILITY_H
#define KARM_UTILITY_H
#include "karmutility.h"
long addTaskTotalTime( long value, Task* task )
QString formatTime( long minutes )
{
if ( task )
return value + task->totalTime();
return value;
QString time;
time.sprintf("%ld:%02ld", minutes / 60, labs(minutes % 60));
return time;
}
long addTaskSessionTime( long value, Task* task )
{
if ( task )
return value + task->sessionTime();
return value;
}
#endif // KARM_UTILITY_H
#ifndef KARMUTILITY_H
#define KARMUTILITY_H
class Task;
#include <qstring.h>
long addTaskTotalTime( long value, Task* task );
long addTaskSessionTime( long value, Task* task );
QString formatTime( long minutes );
#endif
#include <stdlib.h> // abs()
#include <qlabel.h>
#include <qlayout.h>
#include <qlineedit.h>
#include <qlabel.h>
#include "ktimewidget.h"
#include <qstring.h>
#include <qvalidator.h>
#include <kdebug.h>
#include <stdlib.h>
#include <qwidget.h>
#include "ktimewidget.h"
enum ValidatorType { HOUR, MINUTE };
......
#ifndef KTIMEWIDGET_H_
#define KTIMEWIDGET_H_
#ifndef KARM_K_TIME_WIDGET_H
#define KARM_K_TIME_WIDGET_H
class QLineEdit;
class QWidget;
class KarmLineEdit;
/**
......@@ -21,4 +22,4 @@ class KArmTimeWidget : public QWidget
KarmLineEdit *_minuteLE;
};
#endif
#endif // KARM_K_TIME_WIDGET_H
#include "logging.h"
#include "task.h"
#include "preferences.h"
#include <qdatetime.h>
#include <qstring.h>
#include <qfile.h>
#include <qtextstream.h>
#include <qstring.h>
#include <qstylesheet.h>
#include <qtextstream.h>
#include <kdebug.h>
#include "kdebug.h" // kdWarning
#include "logging.h"
#include "preferences.h"
#include "task.h"
#define QSl1(c) QString::fromLatin1(c)
......@@ -26,21 +26,20 @@ QString KarmLogEvent::escapeXML(const QString& string )
return result;
}
// Common LogEvent stuff
//------------------------ Common LogEvent stuff ------------------------
//
void KarmLogEvent::loadCommonFields( Task *task)
{
eventTime = QDateTime::currentDateTime();
QListViewItem *item = task;
fullName = escapeXML(task->name());
while( ( item = item->parent() ) )
while( ( task = task->parent() ) )
{
fullName = escapeXML(((Task *)item)->name()) + fullName.prepend('/');
fullName = escapeXML(task->name()) + fullName.prepend('/');
}
}
// Start LogEvent
//------------------------- Start Task LogEvent ----------------------------
//
StartLogEvent::StartLogEvent( Task *task )
{
......@@ -49,14 +48,14 @@ StartLogEvent::StartLogEvent( Task *task )
QString StartLogEvent::toXML()
{
return QSl1("<starting "
return QSl1("<starting "
" date=\"%1\""
" task=\"%2\" />\n"
).arg( eventTime.toString() ).arg(
fullName );
).arg( eventTime.toString() ).arg(
fullName );
}
// Stop LogEvent
//------------------------- Stop Task LogEvent ---------------------------
//
StopLogEvent::StopLogEvent( Task *task )
{
......@@ -65,14 +64,14 @@ StopLogEvent::StopLogEvent( Task *task )
QString StopLogEvent::toXML()
{
return QSl1("<stopping "
return QSl1("<stopping "
" date=\"%1\""
" task=\"%2\" />\n"
).arg( eventTime.toString() ).arg(
fullName );
fullName );
}
// Rename LogEvent
//------------------------ Rename Task LogEvent ---------------------------
//
RenameLogEvent::RenameLogEvent( Task *task, QString& old )
{
......@@ -82,76 +81,103 @@ RenameLogEvent::RenameLogEvent( Task *task, QString& old )
QString RenameLogEvent::toXML()
{
return QSl1("<renaming "
return QSl1("<renaming "
" date=\"%1\""
" task=\"%2\""
" old_name=\"%3\" />\n"
).arg( eventTime.toString() ).arg(
fullName ).arg(
oldName );
fullName ).arg(
oldName );
}
// Set Session Time LogEvent
//---------------------- Change Times LogEvent ---------------------------
//
SessionTimeLogEvent::SessionTimeLogEvent( Task *task, long total, long change)
TimechangeLogEvent::TimechangeLogEvent( Task *task, long changeSession,
long changeTime)
{
loadCommonFields(task);
delta = change;
newTotal = total;
deltaSession = changeSession;
deltaTime = changeTime;
newSession = task->sessionTime();
newTime = task->time();
}
QString SessionTimeLogEvent::toXML()
QString TimechangeLogEvent::toXML()
{
return QSl1("<new_session_time"
return QSl1("<timechange "
" date=\"%1\""
" task=\"%2\""
" new_total=\"%3\""
" change=\"%4\" />\n"
" new_session=\"%3\""
" change_session=\"%4\""
" new_time=\"%5\""
" change=\"%6\" />\n"
).arg( eventTime.toString() ).arg(
fullName ).arg(
newTotal ).arg(
delta );
fullName ).arg(
newSession ).arg(
deltaSession ).arg(
newTime ).arg(
deltaTime );
}
// Set Total Time LogEvent
//------------------- Add Comment to Task LogEvent ----------------------
//
TotalTimeLogEvent::TotalTimeLogEvent( Task *task, long total, long change)
CommentLogEvent::CommentLogEvent( Task *task, QString& newComment)
{
loadCommonFields(task);
delta = change;
newTotal = total;
comment = newComment;
}
QString TotalTimeLogEvent::toXML()
QString CommentLogEvent::toXML()
{
return QSl1("<new_total_time "
return QSl1("<comment "
" date=\"%1\""
" task=\"%2\""
" new_total=\"%3\""
" change=\"%4\" />\n"
" text=\"%3\" />\n"
).arg( eventTime.toString() ).arg(
fullName ).arg(
newTotal ).arg(
delta );
fullName ).arg(
comment );
}
// Add Comment LogEvent
//--------------------- Remove Task LogEvent ---------------------------
//
CommentLogEvent::CommentLogEvent( Task *task, QString& newComment)
RemoveLogEvent::RemoveLogEvent( Task *task )
{
loadCommonFields(task);
comment = newComment;
}
QString CommentLogEvent::toXML()
QString RemoveLogEvent::toXML()
{
return QSl1("<comment "
return QSl1("<deleted "
" date=\"%1\""
" task=\"%2\""
" text=\"%3\" />\n"
" task=\"%2\" />\n"
).arg( eventTime.toString() ).arg(
fullName ).arg(
comment );
fullName );
}
//--------------------- Start Session LogEvent ---------------------------
//
StartSessionLogEvent::StartSessionLogEvent( )
{
}
QString StartSessionLogEvent::toXML()
{
return QSl1("<start_session"
" date=\"%1\" />\n"
).arg( eventTime.toString() );
}