From 15318cad33835e4e2dc620d033e43cd930676cdd Mon Sep 17 00:00:00 2001 From: kergoth Date: Fri, 25 Jan 2002 22:14:26 +0000 Subject: Initial revision --- (limited to 'core/pim/todo') diff --git a/core/pim/todo/.cvsignore b/core/pim/todo/.cvsignore new file mode 100644 index 0000000..5ed04d8 --- a/dev/null +++ b/core/pim/todo/.cvsignore @@ -0,0 +1,4 @@ +moc_* +Makefile +todoentry.h +todoentry.cpp diff --git a/core/pim/todo/Makefile.in b/core/pim/todo/Makefile.in new file mode 100644 index 0000000..f3c5f0e --- a/dev/null +++ b/core/pim/todo/Makefile.in @@ -0,0 +1,201 @@ +############################################################################# + +####### Compiler, tools and options + +CXX = $(SYSCONF_CXX) $(QT_CXX_MT) +CXXFLAGS= $(SYSCONF_CXXFLAGS_QT) $(SYSCONF_CXXFLAGS) +CC = $(SYSCONF_CC) $(QT_C_MT) +CFLAGS = $(SYSCONF_CFLAGS) +INCPATH = -I$(QPEDIR)/include +LFLAGS = $(SYSCONF_LFLAGS_QT) $(SYSCONF_RPATH_QT) $(SYSCONF_LFLAGS) $(QT_LFLAGS_MT) +LIBS = $(SUBLIBS) -lqpe $(SYSCONF_LIBS_QT) $(SYSCONF_LIBS) $(SYSCONF_LIBS_QTAPP) +MOC = $(SYSCONF_MOC) +UIC = $(SYSCONF_UIC) + +####### Target + +DESTDIR = $(QPEDIR)/bin/ +VER_MAJ = 1 +VER_MIN = 0 +VER_PATCH = 0 +TARGET = todolist +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = mainwindow.h \ + todotable.h \ + todoentryimpl.h +SOURCES = main.cpp \ + mainwindow.cpp \ + todotable.cpp \ + todoentryimpl.cpp +OBJECTS = main.o \ + mainwindow.o \ + todotable.o \ + todoentryimpl.o \ + todoentry.o +INTERFACES = todoentry.ui +UICDECLS = todoentry.h +UICIMPLS = todoentry.cpp +SRCMOC = moc_mainwindow.cpp \ + moc_todotable.cpp \ + moc_todoentryimpl.cpp \ + moc_todoentry.cpp +OBJMOC = moc_mainwindow.o \ + moc_todotable.o \ + moc_todoentryimpl.o \ + moc_todoentry.o + + +####### Implicit rules + +.SUFFIXES: .cpp .cxx .cc .C .c + +.cpp.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cxx.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cc.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.C.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.c.o: + $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $< + +####### Build rules + + +all: $(DESTDIR)$(TARGET) + +$(DESTDIR)$(TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) $(SUBLIBS) + $(SYSCONF_LINK) $(LFLAGS) -o $(DESTDIR)$(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS) + +moc: $(SRCMOC) + +tmake: + tmake todo.pro + +clean: + -rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS) + -rm -f *~ core + -rm -f allmoc.cpp + +####### Extension Modules + +listpromodules: + @echo + +listallmodules: + @echo + +listaddonpromodules: + @echo + +listaddonentmodules: + @echo + + +REQUIRES= + +####### Sub-libraries + + +###### Combined headers + + + +####### Compile + +main.o: main.cpp \ + mainwindow.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +mainwindow.o: mainwindow.cpp \ + mainwindow.h \ + todoentryimpl.h \ + todoentry.h \ + $(QPEDIR)/include/qpe/task.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/stringutil.h \ + todotable.h \ + $(QPEDIR)/include/qpe/categories.h \ + $(QPEDIR)/include/qpe/qpeapplication.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/finddialog.h \ + $(QPEDIR)/include/qpe/global.h \ + $(QPEDIR)/include/qpe/ir.h \ + $(QPEDIR)/include/qpe/qpemenubar.h \ + $(QPEDIR)/include/qpe/qpemessagebox.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/qpetoolbar.h + +todotable.o: todotable.cpp \ + todotable.h \ + $(QPEDIR)/include/qpe/categories.h \ + $(QPEDIR)/include/qpe/task.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/stringutil.h \ + $(QPEDIR)/include/qpe/categoryselect.h \ + $(QPEDIR)/include/qpe/xmlreader.h + +todoentryimpl.o: todoentryimpl.cpp \ + todoentryimpl.h \ + todoentry.h \ + $(QPEDIR)/include/qpe/task.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/stringutil.h \ + $(QPEDIR)/include/qpe/categoryselect.h \ + $(QPEDIR)/include/qpe/datebookmonth.h \ + $(QPEDIR)/include/qpe/event.h \ + $(QPEDIR)/include/qpe/global.h \ + $(QPEDIR)/include/qpe/imageedit.h \ + $(QPEDIR)/include/qpe/timestring.h + +todoentry.h: todoentry.ui + $(UIC) todoentry.ui -o $(INTERFACE_DECL_PATH)/todoentry.h + +todoentry.cpp: todoentry.ui + $(UIC) todoentry.ui -i todoentry.h -o todoentry.cpp + +todoentry.o: todoentry.cpp \ + todoentry.h \ + todoentry.ui + +moc_mainwindow.o: moc_mainwindow.cpp \ + mainwindow.h + +moc_todotable.o: moc_todotable.cpp \ + todotable.h \ + $(QPEDIR)/include/qpe/categories.h \ + $(QPEDIR)/include/qpe/task.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/stringutil.h + +moc_todoentryimpl.o: moc_todoentryimpl.cpp \ + todoentryimpl.h \ + todoentry.h \ + $(QPEDIR)/include/qpe/task.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/stringutil.h + +moc_todoentry.o: moc_todoentry.cpp \ + todoentry.h + +moc_mainwindow.cpp: mainwindow.h + $(MOC) mainwindow.h -o moc_mainwindow.cpp + +moc_todotable.cpp: todotable.h + $(MOC) todotable.h -o moc_todotable.cpp + +moc_todoentryimpl.cpp: todoentryimpl.h + $(MOC) todoentryimpl.h -o moc_todoentryimpl.cpp + +moc_todoentry.cpp: todoentry.h + $(MOC) todoentry.h -o moc_todoentry.cpp + + diff --git a/core/pim/todo/main.cpp b/core/pim/todo/main.cpp new file mode 100644 index 0000000..4e1c8a1 --- a/dev/null +++ b/core/pim/todo/main.cpp @@ -0,0 +1,36 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "mainwindow.h" + +#include + +int main( int argc, char **argv ) +{ + QPEApplication a( argc, argv ); + + TodoWindow mw; + QObject::connect( &a, SIGNAL( flush() ), &mw, SLOT( flush() ) ); + QObject::connect( &a, SIGNAL( reload() ), &mw, SLOT( reload() ) ); + + a.showMainWidget(&mw); + + return a.exec(); +} diff --git a/core/pim/todo/mainwindow.cpp b/core/pim/todo/mainwindow.cpp new file mode 100644 index 0000000..fb85a09 --- a/dev/null +++ b/core/pim/todo/mainwindow.cpp @@ -0,0 +1,466 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "mainwindow.h" +#include "todoentryimpl.h" +#include "todotable.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +static QString todolistXMLFilename() +{ + return Global::applicationFileName("todolist","todolist.xml"); +} + +static QString categoriesXMLFilename() +{ + return Global::applicationFileName("todolist","categories.xml"); +} + +TodoWindow::TodoWindow( QWidget *parent, const char *name, WFlags f = 0 ) : + QMainWindow( parent, name, f ), syncing(FALSE) +{ +// QTime t; +// t.start(); + + setCaption( tr("Todo") ); + QString str; + table = new TodoTable( this ); + table->setColumnWidth( 2, 10 ); + table->setPaintingEnabled( FALSE ); + table->setUpdatesEnabled( FALSE ); + table->viewport()->setUpdatesEnabled( FALSE ); + + { + str = todolistXMLFilename(); + if ( str.isNull() ) + QMessageBox::critical( this, + tr("Out of Space"), + tr("Unable to create startup files\n" + "Free up some space\n" + "before you enter any data") ); + else + table->load( str ); + } + + // repeat for categories... + str = categoriesXMLFilename(); + if ( str.isNull() ) + QMessageBox::critical( this, + tr( "Out of Space" ), + tr( "Unable to create startup files\n" + "Free up some space\n" + "before you enter any data") ); + + setCentralWidget( table ); + setToolBarsMovable( FALSE ); + +// qDebug("after load: t=%d", t.elapsed() ); + + Config config( "todo" ); + config.setGroup( "View" ); + bool complete = config.readBoolEntry( "ShowComplete", true ); + table->setShowCompleted( complete ); + QString category = config.readEntry( "Category", QString::null ); + table->setShowCategory( category ); + + QPEToolBar *bar = new QPEToolBar( this ); + bar->setHorizontalStretchable( TRUE ); + + QPEMenuBar *mb = new QPEMenuBar( bar ); + + catMenu = new QPopupMenu( this ); + QPopupMenu *edit = new QPopupMenu( this ); + contextMenu = new QPopupMenu( this ); + + bar = new QPEToolBar( this ); + + QAction *a = new QAction( tr( "New Task" ), Resource::loadPixmap( "new" ), + QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), + this, SLOT( slotNew() ) ); + a->addTo( bar ); + a->addTo( edit ); + a = new QAction( tr( "Edit" ), Resource::loadIconSet( "edit" ), + QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), + this, SLOT( slotEdit() ) ); + a->addTo( bar ); + a->addTo( edit ); + a->addTo( contextMenu ); + a->setEnabled( FALSE ); + editAction = a; + a = new QAction( tr( "Delete" ), Resource::loadIconSet( "trash" ), + QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), + this, SLOT( slotDelete() ) ); + a->addTo( bar ); + a->addTo( edit ); + a->addTo( contextMenu ); + a->setEnabled( FALSE ); + deleteAction = a; + + if ( Ir::supported() ) { + a = new QAction( tr( "Beam" ), Resource::loadPixmap( "beam" ), + QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), + this, SLOT( slotBeam() ) ); + a->addTo( edit ); + a->addTo( bar ); + } + + a = new QAction( tr( "Find" ), Resource::loadIconSet( "mag" ), + QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), + this, SLOT( slotFind() ) ); + a->addTo( bar ); + a->addTo( edit ); + if ( table->numRows() ) + a->setEnabled( TRUE ); + else + a->setEnabled( FALSE ); + + //a->setEnabled( FALSE ); + findAction = a; +// qDebug("mainwindow #2: t=%d", t.elapsed() ); + + completedAction = new QAction( QString::null, tr("Completed tasks"), 0, this, 0, TRUE ); + + catMenu->setCheckable( true ); + populateCategories(); + + mb->insertItem( tr( "Task" ), edit ); + mb->insertItem( tr( "View" ), catMenu ); + + resize( 200, 300 ); + if ( table->numRows() > 0 ) + currentEntryChanged( 0, 0 ); + connect( table, SIGNAL( signalEdit() ), + this, SLOT( slotEdit() ) ); + connect( table, SIGNAL(signalShowMenu(const QPoint &)), + this, SLOT( slotShowPopup(const QPoint &)) ); + +// qDebug("mainwindow #3: t=%d", t.elapsed() ); + table->updateVisible(); + table->setUpdatesEnabled( TRUE ); + table->setPaintingEnabled( TRUE ); + table->viewport()->setUpdatesEnabled( TRUE ); + + connect( completedAction, SIGNAL( toggled(bool) ), this, SLOT( showCompleted(bool) ) ); + connect( catMenu, SIGNAL(activated(int)), this, SLOT(setCategory(int)) ); + connect( table, SIGNAL( currentChanged( int, int ) ), + this, SLOT( currentEntryChanged( int, int ) ) ); + +// qDebug("done: t=%d", t.elapsed() ); +} + +void TodoWindow::slotNew() +{ + if(syncing) { + QMessageBox::warning(this, tr("Todo"), + tr("Can not edit data, currently syncing")); + return; + } + + int id; + id = -1; + QArray ids; + ids = table->currentEntry().categories(); + if ( ids.count() ) + id = ids[0]; + NewTaskDialog e( id, this, 0, TRUE ); + + Task todo; + +#if defined(Q_WS_QWS) || defined(_WS_QWS_) + e.showMaximized(); +#endif + int ret = e.exec(); + + if ( ret == QDialog::Accepted ) { + table->setPaintingEnabled( false ); + todo = e.todoEntry(); + todo.assignUid(); + table->addEntry( todo ); + table->setPaintingEnabled( true ); + findAction->setEnabled( TRUE ); + } + // I'm afraid we must call this every time now, otherwise + // spend expensive time comparing all these strings... + populateCategories(); +} + +TodoWindow::~TodoWindow() +{ +} + +void TodoWindow::slotDelete() +{ + if(syncing) { + QMessageBox::warning(this, tr("Todo"), + tr("Can not edit data, currently syncing")); + return; + } + + if ( table->currentRow() == -1 ) + return; + + QString strName = table->text( table->currentRow(), 2 ).left( 30 ); + + if ( !QPEMessageBox::confirmDelete( this, tr( "Todo" ), strName ) ) + return; + + + + table->setPaintingEnabled( false ); + table->removeCurrentEntry(); + table->setPaintingEnabled( true ); + + if ( table->numRows() == 0 ) { + currentEntryChanged( -1, 0 ); + findAction->setEnabled( FALSE ); + } +} + +void TodoWindow::slotEdit() +{ + if(syncing) { + QMessageBox::warning(this, tr("Todo"), + tr("Can not edit data, currently syncing")); + return; + } + + Task todo = table->currentEntry(); + + NewTaskDialog e( todo, this, 0, TRUE ); + e.setCaption( tr( "Edit Task" ) ); + +#if defined(Q_WS_QWS) || defined(_WS_QWS_) + e.showMaximized(); +#endif + int ret = e.exec(); + + if ( ret == QDialog::Accepted ) { + table->setPaintingEnabled( false ); + todo = e.todoEntry(); + table->replaceCurrentEntry( todo ); + table->setPaintingEnabled( true ); + } + populateCategories(); + +} + +void TodoWindow::slotShowPopup( const QPoint &p ) +{ + contextMenu->popup( p ); +} + +void TodoWindow::showCompleted( bool s ) +{ + if ( !table->isUpdatesEnabled() ) + return; + table->setPaintingEnabled( false ); + table->setShowCompleted( s ); + table->setPaintingEnabled( true ); +} + +void TodoWindow::currentEntryChanged( int r, int ) +{ + if ( r != -1 && table->rowHeight( r ) > 0 ) { + editAction->setEnabled( TRUE ); + deleteAction->setEnabled( TRUE ); + } else { + editAction->setEnabled( FALSE ); + deleteAction->setEnabled( FALSE ); + } +} + +void TodoWindow::setCategory( int c ) +{ + if ( c <= 0 ) return; + if ( !table->isUpdatesEnabled() ) + return; + table->setPaintingEnabled( false ); + for ( unsigned int i = 1; i < catMenu->count(); i++ ) + catMenu->setItemChecked( i, c == (int)i ); + if ( c == 1 ) { + table->setShowCategory( QString::null ); + setCaption( tr("Todo") + " - " + tr( "All" ) ); + } else if ( c == (int)catMenu->count() - 1 ) { + table->setShowCategory( tr( "Unfiled" ) ); + setCaption( tr("Todo") + " - " + tr( "Unfiled" ) ); + } else { + QString cat = table->categories()[c - 2]; + table->setShowCategory( cat ); + setCaption( tr("Todo") + " - " + cat ); + } + table->setPaintingEnabled( true ); +} + +void TodoWindow::populateCategories() +{ + catMenu->clear(); + + completedAction->addTo( catMenu ); + completedAction->setOn( table->showCompleted() ); + + int id, + rememberId; + id = 1; + catMenu->insertItem( tr( "All" ), id++ ); +// catMenu->insertSeparator(); + QStringList categories = table->categories(); + categories.append( tr( "Unfiled" ) ); + for ( QStringList::Iterator it = categories.begin(); + it != categories.end(); ++it ) { + catMenu->insertItem( *it, id ); + if ( *it == table->showCategory() ) + rememberId = id; + ++id; + } + if ( table->showCategory().isEmpty() ) + setCategory( 1 ); + else + setCategory( rememberId ); +} + +void TodoWindow::reload() +{ + table->clear(); + table->load( todolistXMLFilename() ); + syncing = FALSE; +} + +void TodoWindow::flush() +{ + syncing = TRUE; + table->save( todolistXMLFilename() ); +} + +void TodoWindow::closeEvent( QCloseEvent *e ) +{ + if(syncing) { + /* no need to save if in the middle of syncing */ + e->accept(); + return; + } + + if ( table->save( todolistXMLFilename() ) ) { + e->accept(); + // repeat for categories... + // if writing configs fail, it will emit an + // error, but I feel that it is "ok" for us to exit + // espically since we aren't told if the write succeeded... + Config config( "todo" ); + config.setGroup( "View" ); + config.writeEntry( "ShowComplete", table->showCompleted() ); + config.writeEntry( "Category", table->showCategory() ); + } else { + if ( QMessageBox::critical( this, tr("Out of space"), + tr("Todo was unable\n" + "to save your changes.\n" + "Free up some space\n" + "and try again.\n" + "\nQuit Anyway?"), + QMessageBox::Yes|QMessageBox::Escape, + QMessageBox::No|QMessageBox::Default) + != QMessageBox::No ) + e->accept(); + else + e->ignore(); + } +} + +void TodoWindow::slotFind() +{ + // put everything back to view all for searching... + if ( !catMenu->isItemChecked( 0 ) ) + setCategory( 0 ); + + FindDialog dlg( "Todo List", this ); + QObject::connect( &dlg, + SIGNAL(signalFindClicked(const QString &, + bool, bool, int)), + table, + SLOT(slotDoFind(const QString&, bool, bool, int)) ); + QObject::connect( table, SIGNAL(signalNotFound()), &dlg, + SLOT(slotNotFound()) ); + QObject::connect( table, SIGNAL(signalWrapAround()), &dlg, + SLOT(slotWrapAround()) ); + dlg.exec(); + if ( table->numSelections() ) + table->clearSelection(); + table->clearFindRow(); +} + + +void TodoWindow::setDocument( const QString &filename ) +{ + if ( filename.find(".vcs") != int(filename.length()) - 4 ) return; + + QValueList tl = Task::readVCalendar( filename ); + for( QValueList::Iterator it = tl.begin(); it != tl.end(); ++it ) { + table->addEntry( *it ); + } +} + +static const char * beamfile = "/tmp/obex/todo.vcs"; + +void TodoWindow::slotBeam() +{ + unlink( beamfile ); // delete if exists + Task c = table->currentEntry(); + mkdir("/tmp/obex/", 0755); + Task::writeVCalendar( beamfile, c ); + Ir *ir = new Ir( this ); + connect( ir, SIGNAL( done( Ir * ) ), this, SLOT( beamDone( Ir * ) ) ); + QString description = c.description(); + ir->send( beamfile, description, "text/x-vCalendar" ); +} + +void TodoWindow::beamDone( Ir *ir ) +{ + delete ir; + unlink( beamfile ); +} diff --git a/core/pim/todo/mainwindow.h b/core/pim/todo/mainwindow.h new file mode 100644 index 0000000..f4fcd1b --- a/dev/null +++ b/core/pim/todo/mainwindow.h @@ -0,0 +1,73 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +class TodoTable; +class QAction; +class QPopupMenu; +class Ir; + +class TodoWindow : public QMainWindow +{ + Q_OBJECT + +public: + TodoWindow( QWidget *parent = 0, const char *name = 0, WFlags f = 0 ); + ~TodoWindow(); + +public slots: + void flush(); + void reload(); + +protected slots: + void slotNew(); + void slotDelete(); + void slotEdit(); + void slotShowPopup( const QPoint & ); + void showCompleted( bool ); + void currentEntryChanged( int r, int c ); + void setCategory( int ); + void slotFind(); + void setDocument( const QString & ); + void slotBeam(); + void beamDone( Ir * ); + +protected: + void closeEvent( QCloseEvent *e ); + +private: + void populateCategories(); + +private: + TodoTable *table; + QAction *editAction, + *deleteAction, + *findAction, + * completedAction; + QPopupMenu *contextMenu, *catMenu; + + bool syncing; +}; + +#endif diff --git a/core/pim/todo/qpe-todo.control b/core/pim/todo/qpe-todo.control new file mode 100644 index 0000000..80195a0 --- a/dev/null +++ b/core/pim/todo/qpe-todo.control @@ -0,0 +1,9 @@ +Files: bin/todolist apps/Applications/todo.desktop +Priority: optional +Section: qpe/applications +Maintainer: Warwick Allison +Architecture: arm +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: TODO-list manager + A Todo-list manager for the Qtopia environment. diff --git a/core/pim/todo/todo.pro b/core/pim/todo/todo.pro new file mode 100644 index 0000000..e28ea1c --- a/dev/null +++ b/core/pim/todo/todo.pro @@ -0,0 +1,19 @@ +TEMPLATE = app +CONFIG = qt warn_on release +DESTDIR = $(QPEDIR)/bin +HEADERS = mainwindow.h \ + todotable.h \ + todoentryimpl.h +SOURCES = main.cpp \ + mainwindow.cpp \ + todotable.cpp \ + todoentryimpl.cpp + +INTERFACES = todoentry.ui + +TARGET = todolist +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe + +TRANSLATIONS = ../i18n/de/todolist.ts diff --git a/core/pim/todo/todoentry.ui b/core/pim/todo/todoentry.ui new file mode 100644 index 0000000..c735e76 --- a/dev/null +++ b/core/pim/todo/todoentry.ui @@ -0,0 +1,266 @@ + +NewTaskDialogBase +********************************************************************* +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +********************************************************************* + + QDialog + + name + NewTaskDialogBase + + + geometry + + 0 + 0 + 249 + 321 + + + + caption + New Task + + + layoutMargin + + + layoutSpacing + + + + margin + 0 + + + spacing + 0 + + + QLayoutWidget + + name + Layout4 + + + + margin + 0 + + + spacing + 6 + + + QLabel + + name + TextLabel2 + + + text + Priority: + + + + QComboBox + + + text + 1 - Very High + + + + + text + 2 - High + + + + + text + 3 - Normal + + + + + text + 4 - Low + + + + + text + 5 - Very Low + + + + name + comboPriority + + + sizePolicy + + 7 + 0 + + + + currentItem + 2 + + + + + + QLayoutWidget + + name + Layout3 + + + + margin + 0 + + + spacing + 6 + + + QLabel + + name + TextLabel3 + + + frameShape + NoFrame + + + text + Category: + + + + CategorySelect + + name + comboCategory + + + + + + QLayoutWidget + + name + Layout4 + + + + margin + 0 + + + spacing + 6 + + + QCheckBox + + name + checkCompleted + + + text + &Completed + + + + QCheckBox + + name + checkDate + + + text + D&ue + + + + QPushButton + + name + buttonDate + + + enabled + false + + + text + 1 Jan 2001 + + + + + + QMultiLineEdit + + name + txtTodo + + + + + + + CategorySelect +
qpe/categoryselect.h
+ + -1 + -1 + + 0 + + 7 + 1 + + image0 +
+
+ + + image0 + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + + + + checkDate + toggled(bool) + buttonDate + setEnabled(bool) + + dateChanged( const QString & ) + dateChanged( int, int, int ) + +
diff --git a/core/pim/todo/todoentryimpl.cpp b/core/pim/todo/todoentryimpl.cpp new file mode 100644 index 0000000..79206de --- a/dev/null +++ b/core/pim/todo/todoentryimpl.cpp @@ -0,0 +1,142 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "todoentryimpl.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +NewTaskDialog::NewTaskDialog( const Task& task, QWidget *parent, + const char *name, bool modal, WFlags fl ) + : NewTaskDialogBase( parent, name, modal, fl ), + todo( task ) +{ + todo.setCategories( task.categories() ); + if ( todo.hasDueDate() ) + date = todo.dueDate(); + else + date = QDate::currentDate(); + + init(); + comboPriority->setCurrentItem( task.priority() - 1 ); + + checkCompleted->setChecked( task.isCompleted() ); + checkDate->setChecked( task.hasDueDate() ); + buttonDate->setText( TimeString::longDateString( date ) ); + + txtTodo->setText( task.description() ); +} + +/* + * Constructs a NewTaskDialog which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ +NewTaskDialog::NewTaskDialog( int id, QWidget* parent, const char* name, bool modal, + WFlags fl ) + : NewTaskDialogBase( parent, name, modal, fl ), + date( QDate::currentDate() ) +{ + if ( id != -1 ) { + QArray ids( 1 ); + ids[0] = id; + todo.setCategories( ids ); + } + init(); +} + +void NewTaskDialog::init() +{ + QPopupMenu *m1 = new QPopupMenu( this ); + picker = new DateBookMonth( m1, 0, TRUE ); + m1->insertItem( picker ); + buttonDate->setPopup( m1 ); + comboCategory->setCategories( todo.categories(), "Todo List", tr("Todo List") ); + + connect( picker, SIGNAL( dateClicked( int, int, int ) ), + this, SLOT( dateChanged( int, int, int ) ) ); + + buttonDate->setText( TimeString::longDateString( date ) ); + picker->setDate( date.year(), date.month(), date.day() ); +} + +/* + * Destroys the object and frees any allocated resources + */ +NewTaskDialog::~NewTaskDialog() +{ + // no need to delete child widgets, Qt does it all for us +} +void NewTaskDialog::dateChanged( int y, int m, int d ) +{ + date = QDate( y, m, d ); + buttonDate->setText( TimeString::longDateString( date ) ); +} + +/*! +*/ + +Task NewTaskDialog::todoEntry() +{ + todo.setDueDate( date, checkDate->isChecked() ); + if ( comboCategory->currentCategory() != -1 ) { + todo.setCategories( comboCategory->currentCategories() ); + } + todo.setPriority( comboPriority->currentItem() + 1 ); + todo.setCompleted( checkCompleted->isChecked() ); + + todo.setDescription( txtTodo->text() ); + + return todo; +} + + +/*! + +*/ + +void NewTaskDialog::accept() +{ + QString strText = txtTodo->text(); + if ( !strText || strText == "") { + // hmm... just decline it then, the user obviously didn't care about it + QDialog::reject(); + return; + } + QDialog::accept(); +} diff --git a/core/pim/todo/todoentryimpl.h b/core/pim/todo/todoentryimpl.h new file mode 100644 index 0000000..932d66e --- a/dev/null +++ b/core/pim/todo/todoentryimpl.h @@ -0,0 +1,61 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef NEWTASKDIALOG_H +#define NEWTASKDIALOG_H + +#include "todoentry.h" + +#include + +#include +#include + +class QLabel; +class QTimer; +class DateBookMonth; + +class NewTaskDialog : public NewTaskDialogBase +{ + Q_OBJECT + +public: + NewTaskDialog( const Task &task, QWidget *parent = 0, const char* name = 0, + bool modal = FALSE, WFlags fl = 0 ); + NewTaskDialog( int id, QWidget* parent = 0, const char* name = 0, + bool modal = FALSE, WFlags fl = 0 ); + ~NewTaskDialog(); + + Task todoEntry(); + +protected slots: + void dateChanged( int y, int m, int d ); + +protected: + virtual void accept(); + +private: + void init(); + Task todo; + QDate date; + DateBookMonth *picker; +}; + +#endif // NEWTASKDIALOG_H diff --git a/core/pim/todo/todotable.cpp b/core/pim/todo/todotable.cpp new file mode 100644 index 0000000..77d3389 --- a/dev/null +++ b/core/pim/todo/todotable.cpp @@ -0,0 +1,859 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "todotable.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + + +static bool taskCompare( const Task &task, const QRegExp &r, int category ); + +static QString journalFileName(); + +CheckItem::CheckItem( QTable *t, const QString &key ) + : QTableItem( t, Never, "" ), checked( FALSE ), sortKey( key ) +{ +} + +QString CheckItem::key() const +{ + return sortKey; +} + +void CheckItem::setChecked( bool b ) +{ + checked = b; + table()->updateCell( row(), col() ); +} + +void CheckItem::toggle() +{ + TodoTable *parent = static_cast(table()); + Task newTodo = parent->currentEntry(); + checked = !checked; + newTodo.setCompleted( checked ); + table()->updateCell( row(), col() ); + parent->replaceCurrentEntry( newTodo, true ); +} + +bool CheckItem::isChecked() const +{ + return checked; +} + +static const int BoxSize = 10; + +void CheckItem::paint( QPainter *p, const QColorGroup &cg, const QRect &cr, + bool ) +{ + p->fillRect( 0, 0, cr.width(), cr.height(), cg.brush( QColorGroup::Base ) ); + + int marg = ( cr.width() - BoxSize ) / 2; + int x = 0; + int y = ( cr.height() - BoxSize ) / 2; + p->setPen( QPen( cg.text() ) ); + p->drawRect( x + marg, y, BoxSize, BoxSize ); + p->drawRect( x + marg+1, y+1, BoxSize-2, BoxSize-2 ); + p->setPen( darkGreen ); + x += 1; + y += 1; + if ( checked ) { + QPointArray a( 7*2 ); + int i, xx, yy; + xx = x+1+marg; + yy = y+2; + for ( i=0; i<3; i++ ) { + a.setPoint( 2*i, xx, yy ); + a.setPoint( 2*i+1, xx, yy+2 ); + xx++; yy++; + } + yy -= 2; + for ( i=3; i<7; i++ ) { + a.setPoint( 2*i, xx, yy ); + a.setPoint( 2*i+1, xx, yy+2 ); + xx++; yy--; + } + p->drawLineSegments( a ); + } +} + + +ComboItem::ComboItem( QTable *t, EditType et ) + : QTableItem( t, et, "3" ), cb( 0 ) +{ + setReplaceable( FALSE ); +} + +QWidget *ComboItem::createEditor() const +{ + QString txt = text(); + ( (ComboItem*)this )->cb = new QComboBox( table()->viewport() ); + cb->insertItem( "1" ); + cb->insertItem( "2" ); + cb->insertItem( "3" ); + cb->insertItem( "4" ); + cb->insertItem( "5" ); + cb->setCurrentItem( txt.toInt() - 1 ); + return cb; +} + +void ComboItem::setContentFromEditor( QWidget *w ) +{ + TodoTable *parent = static_cast(table()); + Task newTodo = parent->currentEntry(); + + if ( w->inherits( "QComboBox" ) ) + setText( ( (QComboBox*)w )->currentText() ); + else + QTableItem::setContentFromEditor( w ); + newTodo.setPriority( text().toInt() ); + parent->replaceCurrentEntry( newTodo, true ); +} + +void ComboItem::setText( const QString &s ) +{ + if ( cb ) + cb->setCurrentItem( s.toInt() - 1 ); + QTableItem::setText( s ); +} + +QString ComboItem::text() const +{ + if ( cb ) + return cb->currentText(); + return QTableItem::text(); +} + + + +TodoTable::TodoTable( QWidget *parent, const char *name ) +// #ifdef QT_QTABLE_NOHEADER_CONSTRUCTOR +// : QTable( 0, 3, parent, name, TRUE ), +// #else + : QTable( 0, 3, parent, name ), +// #endif + showComp( true ), + enablePainting( true ), + mCat( 0 ), + currFindRow( -2 ) +{ + mCat.load( categoryFileName() ); + setSorting( TRUE ); + setSelectionMode( NoSelection ); + setColumnStretchable( 2, TRUE ); + setColumnWidth( 0, 20 ); + setColumnWidth( 1, 35 ); + setLeftMargin( 0 ); + verticalHeader()->hide(); + horizontalHeader()->setLabel( 0, tr( "C." ) ); + horizontalHeader()->setLabel( 1, tr( "Prior." ) ); + horizontalHeader()->setLabel( 2, tr( "Description" ) ); + connect( this, SIGNAL( clicked( int, int, int, const QPoint & ) ), + this, SLOT( slotClicked( int, int, int, const QPoint & ) ) ); + connect( this, SIGNAL( pressed( int, int, int, const QPoint & ) ), + this, SLOT( slotPressed( int, int, int, const QPoint & ) ) ); + connect( this, SIGNAL( valueChanged( int, int ) ), + this, SLOT( slotCheckPriority( int, int ) ) ); + connect( this, SIGNAL( currentChanged( int, int ) ), + this, SLOT( slotCurrentChanged( int, int ) ) ); + + menuTimer = new QTimer( this ); + connect( menuTimer, SIGNAL(timeout()), this, SLOT(slotShowMenu()) ); +} + +void TodoTable::addEntry( const Task &todo ) +{ + int row = numRows(); + setNumRows( row + 1 ); + updateJournal( todo, ACTION_ADD ); + insertIntoTable( new Task(todo), row ); + setCurrentCell(row, currentColumn()); + updateVisible(); +} + +void TodoTable::slotClicked( int row, int col, int, const QPoint &pos ) +{ + if ( !cellGeometry( row, col ).contains(pos) ) + return; + // let's switch on the column number... + switch ( col ) + { + case 0: { + CheckItem *i = static_cast(item( row, col )); + if ( i ) { + int x = pos.x() - columnPos( col ); + int y = pos.y() - rowPos( row ); + int w = columnWidth( col ); + int h = rowHeight( row ); + if ( i && x >= ( w - BoxSize ) / 2 && x <= ( w - BoxSize ) / 2 + BoxSize && + y >= ( h - BoxSize ) / 2 && y <= ( h - BoxSize ) / 2 + BoxSize ) { + i->toggle(); + } + emit signalDoneChanged( i->isChecked() ); + } + } + break; + case 1: + break; + case 2: + // may as well edit it... + menuTimer->stop(); +// emit signalEdit(); + break; + } +} + +void TodoTable::slotPressed( int row, int col, int, const QPoint &pos ) +{ + if ( col == 2 && cellGeometry( row, col ).contains(pos) ) + menuTimer->start( 750, TRUE ); +} + +void TodoTable::slotShowMenu() +{ + emit signalShowMenu( QCursor::pos() ); +} + +void TodoTable::slotCurrentChanged( int, int ) +{ + menuTimer->stop(); +} + +void TodoTable::internalAddEntries( QList &list ) +{ + setNumRows( list.count() ); + int row = 0; + Task *it; + for ( it = list.first(); it; it = list.next() ) + insertIntoTable( it, row++ ); +} + + +Task TodoTable::currentEntry() const +{ + QTableItem *i = item( currentRow(), 0 ); + if ( !i || rowHeight( currentRow() ) <= 0 ) + return Task(); + Task *todo = todoList[(CheckItem*)i]; + todo->setCompleted( ( (CheckItem*)item( currentRow(), 0 ) )->isChecked() ); + todo->setPriority( ( (ComboItem*)item( currentRow(), 1 ) )->text().toInt() ); + return *todo; +} + +void TodoTable::replaceCurrentEntry( const Task &todo, bool fromTableItem ) +{ + int row = currentRow(); + updateJournal( todo, ACTION_REPLACE, row ); + + if ( !fromTableItem ) { + journalFreeReplaceEntry( todo, row ); + updateVisible(); + } +} + +void TodoTable::removeCurrentEntry() +{ + Task *oldTodo; + int row = currentRow(); + CheckItem *chk; + + chk = static_cast(item(row, 0 )); + if ( !chk ) + return; + oldTodo = todoList[chk]; + todoList.remove( chk ); + oldTodo->setCompleted( chk->isChecked() ); + oldTodo->setPriority( static_cast(item(row, 1))->text().toInt() ); + realignTable( row ); + updateVisible(); + updateJournal( *oldTodo, ACTION_REMOVE, row ); + delete oldTodo; +} + + +bool TodoTable::save( const QString &fn ) +{ + QString strNewFile = fn + ".new"; + QFile f( strNewFile ); + if ( !f.open( IO_WriteOnly|IO_Raw ) ) + return false; + + QString buf("\n\n"); + QCString str; + int total_written; + + for ( QMap::Iterator it = todoList.begin(); + it != todoList.end(); ++it ) { + if ( !item( it.key()->row(), 0 ) ) + continue; + Task *todo = *it; + // sync item with table + todo->setCompleted( ((CheckItem*)item(it.key()->row(), 0))->isChecked() ); + todo->setPriority( ((ComboItem*)item( it.key()->row(), 1))->text().toInt() ); + buf += "save( buf ); + buf += " />\n"; + str = buf.utf8(); + total_written = f.writeBlock( str.data(), str.length() ); + if ( total_written != int(str.length()) ) { + f.close(); + QFile::remove( strNewFile ); + return false; + } + buf = ""; + } + + buf += "\n"; + str = buf.utf8(); + total_written = f.writeBlock( str.data(), str.length() ); + if ( total_written != int(str.length()) ) { + f.close(); + QFile::remove( strNewFile ); + return false; + } + f.close(); + + // now do the rename + if ( ::rename( strNewFile, fn ) < 0 ) + qWarning( "problem renaming file %s to %s errno %d", + strNewFile.latin1(), fn.latin1(), errno ); + + // remove the journal + QFile::remove( journalFileName() ); + return true; +} + +void TodoTable::load( const QString &fn ) +{ + loadFile( fn, false ); + if ( QFile::exists(journalFileName()) ) { + loadFile( journalFileName(), true ); + save( fn ); + } +// QTable::sortColumn(2,TRUE,TRUE); +// QTable::sortColumn(1,TRUE,TRUE); + QTable::sortColumn(0,TRUE,TRUE); + setCurrentCell( 0, 2 ); +} + +void TodoTable::updateVisible() +{ + if ( !isUpdatesEnabled() ) + return; + +// qDebug("--> updateVisible!"); + + int visible = 0; + int id = mCat.id( "Todo List", showCat ); + for ( int row = 0; row < numRows(); row++ ) { + CheckItem *ci = (CheckItem *)item( row, 0 ); + Task *t = todoList[ci]; + QArray vlCats = t->categories(); + bool hide = false; + if ( !showComp && ci->isChecked() ) + hide = true; + if ( !showCat.isEmpty() ) { + if ( showCat == tr( "Unfiled" ) ) { + if ( vlCats.count() > 0 ) + hide = true; + } else { + // do some comparing, we have to reverse our idea here... + if ( !hide ) { + hide = true; + for ( uint it = 0; it < vlCats.count(); ++it ) { + if ( vlCats[it] == id ) { + hide = false; + break; + } + } + } + } + } + if ( hide ) { + if ( currentRow() == row ) + setCurrentCell( -1, 0 ); + if ( rowHeight( row ) > 0 ) + hideRow( row ); + } else { + if ( rowHeight( row ) == 0 ) { + showRow( row ); + adjustRow( row ); + } + visible++; + } + } + if ( !visible ) + setCurrentCell( -1, 0 ); +} + +void TodoTable::viewportPaintEvent( QPaintEvent *pe ) +{ + if ( enablePainting ) + QTable::viewportPaintEvent( pe ); +} + +void TodoTable::setPaintingEnabled( bool e ) +{ + if ( e != enablePainting ) { + if ( !enablePainting ) { + enablePainting = true; + rowHeightChanged( 0 ); + viewport()->update(); + } else { + enablePainting = false; + } + } +} + +void TodoTable::clear() +{ + for ( QMap::Iterator it = todoList.begin(); + it != todoList.end(); ++it ) { + Task *todo = *it; + delete todo; + } + todoList.clear(); + for ( int r = 0; r < numRows(); ++r ) { + for ( int c = 0; c < numCols(); ++c ) { + if ( cellWidget( r, c ) ) + clearCellWidget( r, c ); + clearCell( r, c ); + } + } + setNumRows( 0 ); +} + +void TodoTable::sortColumn( int col, bool /*ascending*/, bool /*wholeRows*/ ) +{ + // The default for wholeRows is false, however + // for this todo table we want to exchange complete + // rows when sorting. Also, we always want ascending, since + // the values have a logical order. + QTable::sortColumn( col, TRUE, TRUE ); + updateVisible(); +} + +void TodoTable::slotCheckPriority(int row, int col ) +{ + // kludgey work around to make forward along the updated priority... + if ( col == 1 ) { + // let everyone know!! + ComboItem* i = static_cast( item( row, col ) ); + emit signalPriorityChanged( i->text().toInt() ); + } +} + + +void TodoTable::updateJournal( const Task &todo, journal_action action, int row ) +{ + QFile f( journalFileName() ); + if ( !f.open(IO_WriteOnly|IO_Append) ) + return; + QString buf; + QCString str; + buf = " dict( 31 ); + QList list; + dict.setAutoDelete( TRUE ); + dict.insert( "Completed", new int(FCompleted) ); + dict.insert( "HasDate", new int(FHasDate) ); + dict.insert( "Priority", new int(FPriority) ); + dict.insert( "Categories", new int(FCategories) ); + dict.insert( "Description", new int(FDescription) ); + dict.insert( "DateYear", new int(FDateYear) ); + dict.insert( "DateMonth", new int(FDateMonth) ); + dict.insert( "DateDay", new int(FDateDay) ); + dict.insert( "Uid", new int(FUid) ); + dict.insert( "Action", new int(FAction) ); + dict.insert( "Row", new int(FRow) ); + + QByteArray ba = f.readAll(); + f.close(); + char* dt = ba.data(); + int len = ba.size(); + bool hasDueDate = FALSE; + + action = ACTION_ADD; + int i = 0; + char *point; + while ( ( point = strstr( dt+i, "= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) + break; + // we have another attribute, read it. + int j = i; + while ( j < len && dt[j] != '=' ) + ++j; + char *attr = dt+i; + dt[j] = '\0'; + i = ++j; // skip = + while ( i < len && dt[i] != '"' ) + ++i; + j = ++i; + bool haveUtf = FALSE; + bool haveEnt = FALSE; + while ( j < len && dt[j] != '"' ) { + if ( ((unsigned char)dt[j]) > 0x7f ) + haveUtf = TRUE; + if ( dt[j] == '&' ) + haveEnt = TRUE; + ++j; + } + if ( i == j ) { + // empty value + i = j + 1; + continue; + } + QCString value( dt+i, j-i+1 ); + i = j + 1; + int *lookup = dict[ attr ]; + if ( !lookup ) { + todo->setCustomField(attr, value); + continue; + } + switch( *lookup ) { + case FCompleted: + todo->setCompleted( value.toInt() ); + break; + case FHasDate: + // leave... + hasDueDate = value.toInt(); + break; + case FPriority: + todo->setPriority( value.toInt() ); + break; + case FCategories: { + //QString str = Qtopia::plainString( value ); + todo->setCategories( Qtopia::Record::idsFromString( value ) ); + break; + } + case FDescription: + { + QString str = (haveUtf ? QString::fromUtf8( value ) + : QString::fromLatin1( value ) ); + if ( haveEnt ) + str = Qtopia::plainString( str ); + todo->setDescription( str ); + break; + } + case FDateYear: + dtY = value.toInt(); + break; + case FDateMonth: + dtM = value.toInt(); + break; + case FDateDay: + dtD = value.toInt(); + break; + case FUid: + todo->setUid( value.toInt() ); + break; + case FAction: + action = value.toInt(); + break; + case FRow: + row = value.toInt(); + break; + default: + qDebug( "huh??? missing enum? -- attr.: %s", attr ); + break; + } + } + + if ( dtY != 0 && dtM != 0 && dtD != 0 ) + todo->setDueDate( QDate( dtY, dtM, dtD), hasDueDate ); + else + todo->setHasDueDate( hasDueDate ); + +// if ( categoryList.find( todo.category() ) == categoryList.end() ) +// categoryList.append( todo.category() ); + + + // sadly we can't delay adding of items from the journal to get + // the proper effect, but then, the journal should _never_ be + // that huge + + switch( action ) { + case ACTION_ADD: + if ( fromJournal ) { + int myrows = numRows(); + setNumRows( myrows + 1 ); + insertIntoTable( todo, myrows ); + delete todo; + } else + list.append( todo ); + break; + case ACTION_REMOVE: + journalFreeRemoveEntry( row ); + break; + case ACTION_REPLACE: + journalFreeReplaceEntry( *todo, row ); + delete todo; + break; + default: + break; + } + } +// qDebug("parsing done=%d", t.elapsed() ); + if ( list.count() > 0 ) { + internalAddEntries( list ); + list.clear(); + } +// qDebug("loading done: t=%d", t.elapsed() ); +} + +void TodoTable::journalFreeReplaceEntry( const Task &todo, int row ) +{ + QString strTodo; + strTodo = todo.description().left(40).simplifyWhiteSpace(); + if ( row == -1 ) { + QMapIterator it; + for ( it = todoList.begin(); it != todoList.end(); ++it ) { + if ( *(*it) == todo ) { + row = it.key()->row(); + it.key()->setChecked( todo.isCompleted() ); + static_cast(item(row, 1))->setText( QString::number(todo.priority()) ); + item( row, 2 )->setText( strTodo ); + *(*it) = todo; + } + } + } else { + Task *t = todoList[static_cast(item(row, 0))]; + todoList.remove( static_cast(item(row, 0)) ); + delete t; + static_cast(item(row, 0))->setChecked( todo.isCompleted() ); + static_cast(item(row, 1))->setText( QString::number(todo.priority()) ); + item( row, 2 )->setText( strTodo ); + todoList.insert( static_cast(item(row,0)), new Task(todo) ); + } +} + +void TodoTable::journalFreeRemoveEntry( int row ) +{ + CheckItem *chk; + chk = static_cast(item(row, 0 )); + if ( !chk ) + return; + todoList.remove( chk ); + + realignTable( row ); +} + +void TodoTable::keyPressEvent( QKeyEvent *e ) +{ + if ( e->key() == Key_Space || e->key() == Key_Return ) { + switch ( currentColumn() ) { + case 0: { + CheckItem *i = static_cast(item(currentRow(), + currentColumn())); + if ( i ) + i->toggle(); + break; + } + case 1: + break; + case 2: + emit signalEdit(); + default: + break; + } + } else { + QTable::keyPressEvent( e ); + } +} + +QStringList TodoTable::categories() +{ + // This is called seldom, so calling a load in here + // should be fine. + mCat.load( categoryFileName() ); + QStringList categoryList = mCat.labels( "Todo List" ); + return categoryList; +} + +void TodoTable::slotDoFind( const QString &findString, bool caseSensitive, + bool backwards, int category ) +{ + // we have to iterate through the table, this gives the illusion that + // sorting is actually being used. + if ( currFindRow < -1 ) + currFindRow = currentRow() - 1; + clearSelection( TRUE ); + int rows, + row; + CheckItem *chk; + QRegExp r( findString ); + + r.setCaseSensitive( caseSensitive ); + rows = numRows(); + static bool wrapAround = true; + + if ( !backwards ) { + for ( row = currFindRow + 1; row < rows; row++ ) { + chk = static_cast( item(row, 0) ); + if ( taskCompare(*(todoList[chk]), r, category) ) + break; + } + } else { + for ( row = currFindRow - 1; row > -1; row-- ) { + chk = static_cast( item(row, 0) ); + if ( taskCompare(*(todoList[chk]), r, category) ) + break; + } + } + if ( row >= rows || row < 0 ) { + if ( row < 0 ) + currFindRow = rows; + else + currFindRow = -1; + if ( wrapAround ) + emit signalWrapAround(); + else + emit signalNotFound(); + wrapAround = !wrapAround; + } else { + currFindRow = row; + QTableSelection foundSelection; + foundSelection.init( currFindRow, 0 ); + foundSelection.expandTo( currFindRow, numCols() - 1 ); + addSelection( foundSelection ); + setCurrentCell( currFindRow, numCols() - 1 ); + // we should always be able to wrap around and find this again, + // so don't give confusing not found message... + wrapAround = true; + } +} + +int TodoTable::showCategoryId() const +{ + int id; + id = -1; + // if allcategories are selected, you get unfiled... + if ( showCat != tr( "Unfiled" ) && showCat != tr( "All" ) ) + id = mCat.id( "Todo List", showCat ); + return id; +} + +static bool taskCompare( const Task &task, const QRegExp &r, int category ) +{ + bool returnMe; + QArray cats; + cats = task.categories(); + + returnMe = false; + if ( (category == -1 && cats.count() == 0) || category == -2 ) + returnMe = task.match( r ); + else { + int i; + for ( i = 0; i < int(cats.count()); i++ ) { + if ( cats[i] == category ) { + returnMe = task.match( r ); + break; + } + } + } + return returnMe; +} + +static QString journalFileName() +{ + QString str; + str = getenv( "HOME" ); + str += "/.todojournal"; + return str; +} + +// int TodoTable::rowHeight( int ) const +// { +// return 18; +// } + +// int TodoTable::rowPos( int row ) const +// { +// return 18*row; +// } + +// int TodoTable::rowAt( int pos ) const +// { +// return QMIN( pos/18, numRows()-1 ); +// } diff --git a/core/pim/todo/todotable.h b/core/pim/todo/todotable.h new file mode 100644 index 0000000..4f3a064 --- a/dev/null +++ b/core/pim/todo/todotable.h @@ -0,0 +1,207 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef TODOTABLE_H +#define TODOTABLE_H + +#include +#include +#include + +#include +#include +#include + +class Node; +class QComboBox; +class QTimer; + +class CheckItem : public QTableItem +{ +public: + CheckItem( QTable *t, const QString &sortkey ); + + void setChecked( bool b ); + void toggle(); + bool isChecked() const; + void setKey( const QString &key ) { sortKey = key; } + QString key() const; + + void paint( QPainter *p, const QColorGroup &cg, const QRect &cr, bool selected ); + +private: + bool checked; + QString sortKey; +}; + +class ComboItem : public QTableItem +{ +public: + ComboItem( QTable *t, EditType et ); + QWidget *createEditor() const; + void setContentFromEditor( QWidget *w ); + void setText( const QString &s ); + int alignment() const { return Qt::AlignCenter; } + + QString text() const; + +private: + QGuardedPtr cb; + +}; + +class TodoTextItem : public QTableItem +{ +public: + TodoTextItem( QTable *t, const QString & str ) + :QTableItem( t, QTableItem::Never, str ) {} + + QString key () const { return Qtopia::buildSortKey( text() ); } +}; + + + +enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE }; + +class TodoTable : public QTable +{ + Q_OBJECT + +public: + TodoTable( QWidget *parent = 0, const char * name = 0 ); + void addEntry( const Task &todo ); + void clearFindRow() { currFindRow = -2; } + + Task currentEntry() const; + void replaceCurrentEntry( const Task &todo, bool fromTableItem = false ); + + QStringList categories(); + + void setShowCompleted( bool sc ) { showComp = sc; updateVisible(); } + bool showCompleted() const { return showComp; } + + void setShowCategory( const QString &c ) { showCat = c; updateVisible(); } + const QString &showCategory() const { return showCat; } + int showCategoryId() const; + + bool save( const QString &fn ); + void load( const QString &fn ); + void clear(); + void removeCurrentEntry(); + + void setPaintingEnabled( bool e ); + + virtual void sortColumn( int col, bool ascending, bool /*wholeRows*/ ); + +// int rowHeight( int ) const; +// int rowPos( int row ) const; +// virtual int rowAt( int pos ) const; + +signals: + void signalEdit(); + void signalDoneChanged( bool b ); + void signalPriorityChanged( int i ); + void signalShowMenu( const QPoint & ); + void signalNotFound(); + void signalWrapAround(); + +protected: + void keyPressEvent( QKeyEvent *e ); + +private: + void updateVisible(); + void viewportPaintEvent( QPaintEvent * ); + void internalAddEntries( QList &list); + inline void insertIntoTable( Task *todo, int row ); + void updateJournal( const Task &todo, journal_action action, int row = -1); + void mergeJournal(); + void journalFreeReplaceEntry( const Task &todo, int row ); + void journalFreeRemoveEntry( int row ); + inline void realignTable( int row ); + void loadFile( const QString &strFile, bool fromJournal = false ); + +private slots: + void slotClicked( int row, int col, int button, const QPoint &pos ); + void slotPressed( int row, int col, int button, const QPoint &pos ); + void slotCheckPriority(int row, int col ); + void slotCurrentChanged(int row, int col ); + void slotDoFind( const QString &findString, bool caseSensetive, + bool backwards, int category ); + void slotShowMenu(); + void rowHeightChanged( int row ); + +private: + friend class TodoWindow; + + QMap todoList; + QStringList categoryList; + bool showComp; + QString showCat; + QTimer *menuTimer; + bool enablePainting; + Categories mCat; + int currFindRow; +}; + + +inline void TodoTable::insertIntoTable( Task *todo, int row ) +{ + QString sortKey = (char) ((todo->isCompleted() ? 'a' : 'A') + + todo->priority() ) + + Qtopia::buildSortKey( todo->description() ); + CheckItem *chk = new CheckItem( this, sortKey ); + chk->setChecked( todo->isCompleted() ); + ComboItem *cmb = new ComboItem( this, QTableItem::WhenCurrent ); + cmb->setText( QString::number( todo->priority() ) ); + QTableItem *ti = new TodoTextItem( this, todo->description().left(40).simplifyWhiteSpace() ); + ti->setReplaceable( false ); + + setItem( row, 0, chk ); + setItem( row, 1, cmb ); + setItem( row, 2, ti ); + + todoList.insert( chk, todo ); +} + +inline void TodoTable::realignTable( int row ) +{ + QTableItem *ti1, + *ti2, + *ti3; + int totalRows = numRows(); + for ( int curr = row; curr < totalRows - 1; curr++ ) { + // this is bad, we must take the item out and then + // set it. In the end, it behaves no worse (time wise) + // then the old way of saving the entries to file, clearing + // the table re-reading in the file and resetting the table + ti1 = item( curr + 1, 0 ); + ti2 = item( curr + 1, 1 ); + ti3 = item( curr + 1, 2 ); + takeItem( ti1 ); + takeItem( ti2 ); + takeItem( ti3 ); + setItem( curr, 0, ti1 ); + setItem( curr, 1, ti2 ); + setItem( curr, 2, ti3 ); + } + setNumRows( totalRows - 1 ); +} + +#endif -- cgit v0.9.0.2