summaryrefslogtreecommitdiffstats
path: root/karm/karm_part.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'karm/karm_part.cpp')
-rw-r--r--karm/karm_part.cpp703
1 files changed, 703 insertions, 0 deletions
diff --git a/karm/karm_part.cpp b/karm/karm_part.cpp
new file mode 100644
index 000000000..c7729f0fa
--- /dev/null
+++ b/karm/karm_part.cpp
@@ -0,0 +1,703 @@
+
+#include "kaccelmenuwatch.h"
+#include "karm_part.h"
+#include "karmerrors.h"
+#include "task.h"
+#include "preferences.h"
+#include "tray.h"
+#include "version.h"
+#include <kaccel.h>
+
+#include <kinstance.h>
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kfiledialog.h>
+#include <kglobal.h>
+#include <klocale.h>
+
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qmultilineedit.h>
+#include <qpopupmenu.h>
+#include "mainwindow.h"
+
+karmPart::karmPart( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name )
+ : DCOPObject ( "KarmDCOPIface" ), KParts::ReadWritePart(parent, name),
+ _accel ( new KAccel( parentWidget ) ),
+ _watcher ( new KAccelMenuWatch( _accel, parentWidget ) )
+{
+ // we need an instance
+ setInstance( karmPartFactory::instance() );
+
+ // this should be your custom internal widget
+ _taskView = new TaskView( parentWidget, widgetName );
+
+ // setup PreferenceDialog.
+ _preferences = Preferences::instance();
+
+ // notify the part that this is our internal widget
+ setWidget(_taskView);
+
+ // create our actions
+ KStdAction::open(this, SLOT(fileOpen()), actionCollection());
+ KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());
+ KStdAction::save(this, SLOT(save()), actionCollection());
+
+ makeMenus();
+
+ _watcher->updateMenus();
+
+ // connections
+
+ connect( _taskView, SIGNAL( totalTimesChanged( long, long ) ),
+ this, SLOT( updateTime( long, long ) ) );
+ connect( _taskView, SIGNAL( selectionChanged ( QListViewItem * )),
+ this, SLOT(slotSelectionChanged()));
+ connect( _taskView, SIGNAL( updateButtons() ),
+ this, SLOT(slotSelectionChanged()));
+
+ // Setup context menu request handling
+ connect( _taskView,
+ SIGNAL( contextMenuRequested( QListViewItem*, const QPoint&, int )),
+ this,
+ SLOT( contextMenuRequest( QListViewItem*, const QPoint&, int )));
+
+ _tray = new KarmTray( this );
+
+ connect( _tray, SIGNAL( quitSelected() ), SLOT( quit() ) );
+
+ connect( _taskView, SIGNAL( timersActive() ), _tray, SLOT( startClock() ) );
+ connect( _taskView, SIGNAL( timersActive() ), this, SLOT( enableStopAll() ));
+ connect( _taskView, SIGNAL( timersInactive() ), _tray, SLOT( stopClock() ) );
+ connect( _taskView, SIGNAL( timersInactive() ), this, SLOT( disableStopAll()));
+ connect( _taskView, SIGNAL( tasksChanged( QPtrList<Task> ) ),
+ _tray, SLOT( updateToolTip( QPtrList<Task> ) ));
+
+ _taskView->load();
+
+ // Everything that uses Preferences has been created now, we can let it
+ // emit its signals
+ _preferences->emitSignals();
+ slotSelectionChanged();
+
+ // set our XML-UI resource file
+ setXMLFile("karmui.rc");
+
+ // we are read-write by default
+ setReadWrite(true);
+
+ // we are not modified since we haven't done anything yet
+ setModified(false);
+}
+
+karmPart::~karmPart()
+{
+}
+
+void karmPart::slotSelectionChanged()
+{
+ Task* item= _taskView->current_item();
+ actionDelete->setEnabled(item);
+ actionEdit->setEnabled(item);
+ actionStart->setEnabled(item && !item->isRunning() && !item->isComplete());
+ actionStop->setEnabled(item && item->isRunning());
+ actionMarkAsComplete->setEnabled(item && !item->isComplete());
+ actionMarkAsIncomplete->setEnabled(item && item->isComplete());
+}
+
+void karmPart::makeMenus()
+{
+ KAction
+ *actionKeyBindings,
+ *actionNew,
+ *actionNewSub;
+
+ (void) KStdAction::quit( this, SLOT( quit() ), actionCollection());
+ (void) KStdAction::print( this, SLOT( print() ), actionCollection());
+ actionKeyBindings = KStdAction::keyBindings( this, SLOT( keyBindings() ),
+ actionCollection() );
+ actionPreferences = KStdAction::preferences(_preferences,
+ SLOT(showDialog()),
+ actionCollection() );
+ (void) KStdAction::save( this, SLOT( save() ), actionCollection() );
+ KAction* actionStartNewSession = new KAction( i18n("Start &New Session"),
+ 0,
+ this,
+ SLOT( startNewSession() ),
+ actionCollection(),
+ "start_new_session");
+ KAction* actionResetAll = new KAction( i18n("&Reset All Times"),
+ 0,
+ this,
+ SLOT( resetAllTimes() ),
+ actionCollection(),
+ "reset_all_times");
+ actionStart = new KAction( i18n("&Start"),
+ QString::fromLatin1("1rightarrow"), Key_S,
+ _taskView,
+ SLOT( startCurrentTimer() ), actionCollection(),
+ "start");
+ actionStop = new KAction( i18n("S&top"),
+ QString::fromLatin1("stop"), 0,
+ _taskView,
+ SLOT( stopCurrentTimer() ), actionCollection(),
+ "stop");
+ actionStopAll = new KAction( i18n("Stop &All Timers"),
+ Key_Escape,
+ _taskView,
+ SLOT( stopAllTimers() ), actionCollection(),
+ "stopAll");
+ actionStopAll->setEnabled(false);
+
+ actionNew = new KAction( i18n("&New..."),
+ QString::fromLatin1("filenew"), CTRL+Key_N,
+ _taskView,
+ SLOT( newTask() ), actionCollection(),
+ "new_task");
+ actionNewSub = new KAction( i18n("New &Subtask..."),
+ QString::fromLatin1("kmultiple"), CTRL+ALT+Key_N,
+ _taskView,
+ SLOT( newSubTask() ), actionCollection(),
+ "new_sub_task");
+ actionDelete = new KAction( i18n("&Delete"),
+ QString::fromLatin1("editdelete"), Key_Delete,
+ _taskView,
+ SLOT( deleteTask() ), actionCollection(),
+ "delete_task");
+ actionEdit = new KAction( i18n("&Edit..."),
+ QString::fromLatin1("edit"), CTRL + Key_E,
+ _taskView,
+ SLOT( editTask() ), actionCollection(),
+ "edit_task");
+// actionAddComment = new KAction( i18n("&Add Comment..."),
+// QString::fromLatin1("document"),
+// CTRL+ALT+Key_E,
+// _taskView,
+// SLOT( addCommentToTask() ),
+// actionCollection(),
+// "add_comment_to_task");
+ actionMarkAsComplete = new KAction( i18n("&Mark as Complete"),
+ QString::fromLatin1("document"),
+ CTRL+Key_M,
+ _taskView,
+ SLOT( markTaskAsComplete() ),
+ actionCollection(),
+ "mark_as_complete");
+ actionMarkAsIncomplete = new KAction( i18n("&Mark as Incomplete"),
+ QString::fromLatin1("document"),
+ CTRL+Key_M,
+ _taskView,
+ SLOT( markTaskAsIncomplete() ),
+ actionCollection(),
+ "mark_as_incomplete");
+ actionClipTotals = new KAction( i18n("&Copy Totals to Clipboard"),
+ QString::fromLatin1("klipper"),
+ CTRL+Key_C,
+ _taskView,
+ SLOT( clipTotals() ),
+ actionCollection(),
+ "clip_totals");
+ actionClipHistory = new KAction( i18n("Copy &History to Clipboard"),
+ QString::fromLatin1("klipper"),
+ CTRL+ALT+Key_C,
+ _taskView,
+ SLOT( clipHistory() ),
+ actionCollection(),
+ "clip_history");
+
+ new KAction( i18n("Import &Legacy Flat File..."), 0,
+ _taskView, SLOT(loadFromFlatFile()), actionCollection(),
+ "import_flatfile");
+ new KAction( i18n("&Export to CSV File..."), 0,
+ _taskView, SLOT(exportcsvFile()), actionCollection(),
+ "export_csvfile");
+ new KAction( i18n("Export &History to CSV File..."), 0,
+ this, SLOT(exportcsvHistory()), actionCollection(),
+ "export_csvhistory");
+ new KAction( i18n("Import Tasks From &Planner..."), 0,
+ _taskView, SLOT(importPlanner()), actionCollection(),
+ "import_planner");
+ new KAction( i18n("Configure KArm..."), 0,
+ _preferences, SLOT(showDialog()), actionCollection(),
+ "configure_karm");
+
+/*
+ new KAction( i18n("Import E&vents"), 0,
+ _taskView,
+ SLOT( loadFromKOrgEvents() ), actionCollection(),
+ "import_korg_events");
+ */
+
+ // Tool tops must be set after the createGUI.
+ actionKeyBindings->setToolTip( i18n("Configure key bindings") );
+ actionKeyBindings->setWhatsThis( i18n("This will let you configure key"
+ "bindings which is specific to karm") );
+
+ actionStartNewSession->setToolTip( i18n("Start a new session") );
+ actionStartNewSession->setWhatsThis( i18n("This will reset the session time "
+ "to 0 for all tasks, to start a "
+ "new session, without affecting "
+ "the totals.") );
+ actionResetAll->setToolTip( i18n("Reset all times") );
+ actionResetAll->setWhatsThis( i18n("This will reset the session and total "
+ "time to 0 for all tasks, to restart from "
+ "scratch.") );
+
+ actionStart->setToolTip( i18n("Start timing for selected task") );
+ actionStart->setWhatsThis( i18n("This will start timing for the selected "
+ "task.\n"
+ "It is even possible to time several tasks "
+ "simultaneously.\n\n"
+ "You may also start timing of a tasks by "
+ "double clicking the left mouse "
+ "button on a given task. This will, however, "
+ "stop timing of other tasks."));
+
+ actionStop->setToolTip( i18n("Stop timing of the selected task") );
+ actionStop->setWhatsThis( i18n("Stop timing of the selected task") );
+
+ actionStopAll->setToolTip( i18n("Stop all of the active timers") );
+ actionStopAll->setWhatsThis( i18n("Stop all of the active timers") );
+
+ actionNew->setToolTip( i18n("Create new top level task") );
+ actionNew->setWhatsThis( i18n("This will create a new top level task.") );
+
+ actionDelete->setToolTip( i18n("Delete selected task") );
+ actionDelete->setWhatsThis( i18n("This will delete the selected task and "
+ "all its subtasks.") );
+
+ actionEdit->setToolTip( i18n("Edit name or times for selected task") );
+ actionEdit->setWhatsThis( i18n("This will bring up a dialog box where you "
+ "may edit the parameters for the selected "
+ "task."));
+ //actionAddComment->setToolTip( i18n("Add a comment to a task") );
+ //actionAddComment->setWhatsThis( i18n("This will bring up a dialog box where "
+ // "you can add a comment to a task. The "
+ // "comment can for instance add information on what you "
+ // "are currently doing. The comment will "
+ // "be logged in the log file."));
+ actionClipTotals->setToolTip(i18n("Copy task totals to clipboard"));
+ actionClipHistory->setToolTip(i18n("Copy time card history to clipboard."));
+
+ slotSelectionChanged();
+}
+
+void karmPart::setReadWrite(bool rw)
+{
+ // notify your internal widget of the read-write state
+ if (rw)
+ connect(_taskView, SIGNAL(textChanged()),
+ this, SLOT(setModified()));
+ else
+ {
+ disconnect(_taskView, SIGNAL(textChanged()),
+ this, SLOT(setModified()));
+ }
+
+ ReadWritePart::setReadWrite(rw);
+}
+
+void karmPart::setModified(bool modified)
+{
+ // get a handle on our Save action and make sure it is valid
+ KAction *save = actionCollection()->action(KStdAction::stdName(KStdAction::Save));
+ if (!save)
+ return;
+
+ // if so, we either enable or disable it based on the current
+ // state
+ if (modified)
+ save->setEnabled(true);
+ else
+ save->setEnabled(false);
+
+ // in any event, we want our parent to do it's thing
+ ReadWritePart::setModified(modified);
+}
+
+bool karmPart::openFile()
+{
+ // m_file is always local so we can use QFile on it
+ _taskView->load(m_file);
+
+ // just for fun, set the status bar
+ emit setStatusBarText( m_url.prettyURL() );
+
+ return true;
+}
+
+bool karmPart::saveFile()
+{
+ // if we aren't read-write, return immediately
+ if (isReadWrite() == false)
+ return false;
+
+ // m_file is always local, so we use QFile
+ QFile file(m_file);
+ if (file.open(IO_WriteOnly) == false)
+ return false;
+
+ // use QTextStream to dump the text to the file
+ QTextStream stream(&file);
+
+ file.close();
+
+ return true;
+}
+
+void karmPart::fileOpen()
+{
+ // this slot is called whenever the File->Open menu is selected,
+ // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar
+ // button is clicked
+ QString file_name = KFileDialog::getOpenFileName();
+
+ if (file_name.isEmpty() == false)
+ openURL(file_name);
+}
+
+void karmPart::fileSaveAs()
+{
+ // this slot is called whenever the File->Save As menu is selected,
+ QString file_name = KFileDialog::getSaveFileName();
+ if (file_name.isEmpty() == false)
+ saveAs(file_name);
+}
+
+
+// It's usually safe to leave the factory code alone.. with the
+// notable exception of the KAboutData data
+#include <kaboutdata.h>
+#include <klocale.h>
+
+KInstance* karmPartFactory::s_instance = 0L;
+KAboutData* karmPartFactory::s_about = 0L;
+
+karmPartFactory::karmPartFactory()
+ : KParts::Factory()
+{
+}
+
+karmPartFactory::~karmPartFactory()
+{
+ delete s_instance;
+ delete s_about;
+
+ s_instance = 0L;
+}
+
+KParts::Part* karmPartFactory::createPartObject( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name,
+ const char *classname, const QStringList &args )
+{
+ // Create an instance of our Part
+ karmPart* obj = new karmPart( parentWidget, widgetName, parent, name );
+
+ // See if we are to be read-write or not
+ if (QCString(classname) == "KParts::ReadOnlyPart")
+ obj->setReadWrite(false);
+
+ return obj;
+}
+
+KInstance* karmPartFactory::instance()
+{
+ if( !s_instance )
+ {
+ s_about = new KAboutData("karmpart", I18N_NOOP("karmPart"), "0.1");
+ s_about->addAuthor("Thorsten Staerk", 0, "thorsten@staerk.de");
+ s_instance = new KInstance(s_about);
+ }
+ return s_instance;
+}
+
+extern "C"
+{
+ KDE_EXPORT void* init_libkarmpart()
+ {
+ KGlobal::locale()->insertCatalogue("karm");
+ return new karmPartFactory;
+ }
+}
+
+void karmPart::contextMenuRequest( QListViewItem*, const QPoint& point, int )
+{
+ QPopupMenu* pop = dynamic_cast<QPopupMenu*>(
+ factory()->container( i18n( "task_popup" ), this ) );
+ if ( pop )
+ pop->popup( point );
+}
+
+//----------------------------------------------------------------------------
+//
+// D C O P I N T E R F A C E
+//
+//----------------------------------------------------------------------------
+
+QString karmPart::version() const
+{
+ return KARM_VERSION;
+}
+
+QString karmPart::deletetodo()
+{
+ _taskView->deleteTask();
+ return "";
+}
+
+bool karmPart::getpromptdelete()
+{
+ return _preferences->promptDelete();
+}
+
+QString karmPart::setpromptdelete( bool prompt )
+{
+ _preferences->setPromptDelete( prompt );
+ return "";
+}
+
+QString karmPart::taskIdFromName( const QString &taskname ) const
+{
+ QString rval = "";
+
+ Task* task = _taskView->first_child();
+ while ( rval.isEmpty() && task )
+ {
+ rval = _hasTask( task, taskname );
+ task = task->nextSibling();
+ }
+
+ return rval;
+}
+
+void karmPart::quit()
+{
+ // TODO: write something for kapp->quit();
+}
+
+bool karmPart::save()
+{
+ kdDebug(5970) << "Saving time data to disk." << endl;
+ QString err=_taskView->save(); // untranslated error msg.
+ // TODO:
+ /* if (err.isEmpty()) statusBar()->message(i18n("Successfully saved tasks and history"),1807);
+ else statusBar()->message(i18n(err.ascii()),7707); // no msgbox since save is called when exiting */
+ return true;
+}
+
+int karmPart::addTask( const QString& taskname )
+{
+ DesktopList desktopList;
+ QString uid = _taskView->addTask( taskname, 0, 0, desktopList );
+ kdDebug(5970) << "MainWindow::addTask( " << taskname << " ) returns " << uid << endl;
+ if ( uid.length() > 0 ) return 0;
+ else
+ {
+ // We can't really tell what happened, b/c the resource framework only
+ // returns a boolean.
+ return KARM_ERR_GENERIC_SAVE_FAILED;
+ }
+}
+
+QString karmPart::setPerCentComplete( const QString& taskName, int perCent )
+{
+ int index = 0;
+ QString err="no such task";
+ for (int i=0; i<_taskView->count(); i++)
+ {
+ if ((_taskView->item_at_index(i)->name()==taskName))
+ {
+ index=i;
+ if (err==QString::null) err="task name is abigious";
+ if (err=="no such task") err=QString::null;
+ }
+ }
+ if (err==QString::null)
+ {
+ _taskView->item_at_index(index)->setPercentComplete( perCent, _taskView->storage() );
+ }
+ return err;
+}
+
+int karmPart::bookTime
+( const QString& taskId, const QString& datetime, long minutes )
+{
+ int rval = 0;
+ QDate startDate;
+ QTime startTime;
+ QDateTime startDateTime;
+ Task *task, *t;
+
+ if ( minutes <= 0 ) rval = KARM_ERR_INVALID_DURATION;
+
+ // Find task
+ task = _taskView->first_child();
+ t = NULL;
+ while ( !t && task )
+ {
+ t = _hasUid( task, taskId );
+ task = task->nextSibling();
+ }
+ if ( t == NULL ) rval = KARM_ERR_UID_NOT_FOUND;
+
+ // Parse datetime
+ if ( !rval )
+ {
+ startDate = QDate::fromString( datetime, Qt::ISODate );
+ if ( datetime.length() > 10 ) // "YYYY-MM-DD".length() = 10
+ {
+ startTime = QTime::fromString( datetime, Qt::ISODate );
+ }
+ else startTime = QTime( 12, 0 );
+ if ( startDate.isValid() && startTime.isValid() )
+ {
+ startDateTime = QDateTime( startDate, startTime );
+ }
+ else rval = KARM_ERR_INVALID_DATE;
+
+ }
+
+ // Update task totals (session and total) and save to disk
+ if ( !rval )
+ {
+ t->changeTotalTimes( t->sessionTime() + minutes, t->totalTime() + minutes );
+ if ( ! _taskView->storage()->bookTime( t, startDateTime, minutes * 60 ) )
+ {
+ rval = KARM_ERR_GENERIC_SAVE_FAILED;
+ }
+ }
+
+ return rval;
+}
+
+// There was something really bad going on with DCOP when I used a particular
+// argument name; if I recall correctly, the argument name was errno.
+QString karmPart::getError( int mkb ) const
+{
+ if ( mkb <= KARM_MAX_ERROR_NO ) return m_error[ mkb ];
+ else return i18n( "Invalid error number: %1" ).arg( mkb );
+}
+
+int karmPart::totalMinutesForTaskId( const QString& taskId )
+{
+ int rval = 0;
+ Task *task, *t;
+
+ kdDebug(5970) << "MainWindow::totalTimeForTask( " << taskId << " )" << endl;
+
+ // Find task
+ task = _taskView->first_child();
+ t = NULL;
+ while ( !t && task )
+ {
+ t = _hasUid( task, taskId );
+ task = task->nextSibling();
+ }
+ if ( t != NULL )
+ {
+ rval = t->totalTime();
+ kdDebug(5970) << "MainWindow::totalTimeForTask - task found: rval = " << rval << endl;
+ }
+ else
+ {
+ kdDebug(5970) << "MainWindow::totalTimeForTask - task not found" << endl;
+ rval = KARM_ERR_UID_NOT_FOUND;
+ }
+
+ return rval;
+}
+
+QString karmPart::_hasTask( Task* task, const QString &taskname ) const
+{
+ QString rval = "";
+ if ( task->name() == taskname )
+ {
+ rval = task->uid();
+ }
+ else
+ {
+ Task* nexttask = task->firstChild();
+ while ( rval.isEmpty() && nexttask )
+ {
+ rval = _hasTask( nexttask, taskname );
+ nexttask = nexttask->nextSibling();
+ }
+ }
+ return rval;
+}
+
+Task* karmPart::_hasUid( Task* task, const QString &uid ) const
+{
+ Task *rval = NULL;
+
+ //kdDebug(5970) << "MainWindow::_hasUid( " << task << ", " << uid << " )" << endl;
+
+ if ( task->uid() == uid ) rval = task;
+ else
+ {
+ Task* nexttask = task->firstChild();
+ while ( !rval && nexttask )
+ {
+ rval = _hasUid( nexttask, uid );
+ nexttask = nexttask->nextSibling();
+ }
+ }
+ return rval;
+}
+
+QString karmPart::starttimerfor( const QString& taskname )
+{
+ QString err="no such task";
+ for (int i=0; i<_taskView->count(); i++)
+ {
+ if ((_taskView->item_at_index(i)->name()==taskname))
+ {
+ _taskView->startTimerFor( _taskView->item_at_index(i) );
+ err="";
+ }
+ }
+ return err;
+}
+
+QString karmPart::stoptimerfor( const QString& taskname )
+{
+ QString err="no such task";
+ for (int i=0; i<_taskView->count(); i++)
+ {
+ if ((_taskView->item_at_index(i)->name()==taskname))
+ {
+ _taskView->stopTimerFor( _taskView->item_at_index(i) );
+ err="";
+ }
+ }
+ return err;
+}
+
+QString karmPart::exportcsvfile( QString filename, QString from, QString to, int type, bool decimalMinutes, bool allTasks, QString delimiter, QString quote )
+{
+ ReportCriteria rc;
+ rc.allTasks=allTasks;
+ rc.decimalMinutes=decimalMinutes;
+ rc.delimiter=delimiter;
+ rc.from=QDate::fromString( from );
+ rc.quote=quote;
+ rc.reportType=(ReportCriteria::REPORTTYPE) type;
+ rc.to=QDate::fromString( to );
+ rc.url=filename;
+ return _taskView->report( rc );
+}
+
+QString karmPart::importplannerfile( QString fileName )
+{
+ return _taskView->importPlanner(fileName);
+}
+
+void karmPart::startNewSession()
+{
+ _taskView->startNewSession();
+ _taskView->save();
+}
+
+#include <qpopupmenu.h>
+#include "karm_part.moc"