kpilot

todoWidget.cc

Go to the documentation of this file.
00001 /* KPilot
00002 **
00003 ** Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00004 **
00005 ** This file defines the todoWidget, that part of KPilot that
00006 ** displays todo records from the Pilot.
00007 */
00008 
00009 /*
00010 ** This program is free software; you can redistribute it and/or modify
00011 ** it under the terms of the GNU General Public License as published by
00012 ** the Free Software Foundation; either version 2 of the License, or
00013 ** (at your option) any later version.
00014 **
00015 ** This program is distributed in the hope that it will be useful,
00016 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00018 ** GNU General Public License for more details.
00019 **
00020 ** You should have received a copy of the GNU General Public License
00021 ** along with this program in a file called COPYING; if not, write to
00022 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00023 ** MA 02110-1301, USA.
00024 */
00025 
00026 /*
00027 ** Bug reports and questions can be sent to kde-pim@kde.org
00028 */
00029 
00030 #include "options.h"
00031 
00032 #include <qptrlist.h>
00033 #include <klistview.h>
00034 #include <qpushbutton.h>
00035 #include <qlayout.h>
00036 #include <qlabel.h>
00037 #include <qtextview.h>
00038 #include <qcombobox.h>
00039 #include <qwhatsthis.h>
00040 #include <qtextcodec.h>
00041 
00042 #include <kmessagebox.h>
00043 
00044 #include "kpilotConfig.h"
00045 #include "todoEditor.h"
00046 #include "pilotLocalDatabase.h"
00047 #include "todoWidget.moc"
00048 
00049 
00050 
00051 
00052 TodoCheckListItem::TodoCheckListItem(QListView*parent, const QString&text,
00053     recordid_t pilotid, void*r):PilotCheckListItem(parent, text, pilotid, r)
00054 {
00055 
00056 }
00057 
00058 void TodoCheckListItem::stateChange(bool state)
00059 {
00060     TodoListView*par=dynamic_cast<TodoListView*>(listView());
00061     if (par) par->itemWasChecked(this, state);
00062 }
00063 
00064 
00065 
00066 TodoWidget::TodoWidget(QWidget * parent,
00067     const QString & path) :
00068     PilotComponent(parent, "component_todo", path),
00069     fTodoInfo(0L),
00070     fTodoAppInfo(0L),
00071     fTodoDB(0L),
00072     fPendingTodos(0)
00073 {
00074     FUNCTIONSETUP;
00075 
00076     setupWidget();
00077     fTodoList.setAutoDelete(true);
00078 
00079 }
00080 
00081 TodoWidget::~TodoWidget()
00082 {
00083     FUNCTIONSETUP;
00084     KPILOT_DELETE( fTodoDB );
00085 }
00086 
00087 int TodoWidget::getAllTodos(PilotDatabase * todoDB)
00088 {
00089     FUNCTIONSETUP;
00090 
00091     int currentRecord = 0;
00092     PilotRecord *pilotRec;
00093     PilotTodoEntry *todo;
00094 
00095 #ifdef DEBUG
00096     DEBUGKPILOT << fname << ": Reading ToDoDB..." << endl;
00097 #endif
00098 
00099     while ((pilotRec = todoDB->readRecordByIndex(currentRecord)) != 0L)
00100     {
00101         if (!(pilotRec->isDeleted()) &&
00102             (!(pilotRec->isSecret()) || KPilotSettings::showSecrets()))
00103         {
00104             todo = new PilotTodoEntry(pilotRec);
00105             if (todo == 0L)
00106             {
00107                 WARNINGKPILOT << "Couldn't allocate record "
00108                     << currentRecord++
00109                     << endl;
00110                 break;
00111             }
00112             fTodoList.append(todo);
00113         }
00114         KPILOT_DELETE( pilotRec );
00115 
00116         currentRecord++;
00117     }
00118 
00119 #ifdef DEBUG
00120     DEBUGKPILOT << fname
00121         << ": Total " << currentRecord << " records" << endl;
00122 #endif
00123 
00124     return currentRecord;
00125 }
00126 
00127 void TodoWidget::showComponent()
00128 {
00129     FUNCTIONSETUP;
00130     if ( fPendingTodos>0 ) return;
00131 
00132 #ifdef DEBUG
00133     DEBUGKPILOT << fname
00134         << ": Reading from directory " << dbPath() << endl;
00135 #endif
00136 
00137     fTodoDB = new PilotLocalDatabase(dbPath(), CSL1("ToDoDB"));
00138 
00139     fTodoList.clear();
00140 
00141     if (fTodoDB->isOpen())
00142     {
00143         KPILOT_DELETE(fTodoAppInfo);
00144         fTodoAppInfo = new PilotToDoInfo(fTodoDB);
00145         populateCategories(fCatList, fTodoAppInfo->categoryInfo());
00146         getAllTodos(fTodoDB);
00147 
00148     }
00149     else
00150     {
00151         populateCategories(fCatList, 0L);
00152         WARNINGKPILOT << "Could not open local TodoDB" << endl;
00153     }
00154 
00155     KPILOT_DELETE( fTodoDB );
00156 
00157     updateWidget();
00158 }
00159 
00160 /* virtual */ bool TodoWidget::preHotSync(QString &s)
00161 {
00162     FUNCTIONSETUP;
00163 
00164     if (fPendingTodos)
00165     {
00166 #ifdef DEBUG
00167         DEBUGKPILOT << fname
00168             << ": fPendingTodo="
00169             << fPendingTodos
00170             << endl;
00171 #endif
00172 
00173 #if KDE_VERSION<220
00174         s = i18n("There are still %1 to-do editing windows open.")
00175             .arg(QString::number(fPendingTodos));
00176 #else
00177         s = i18n("There is still a to-do editing window open.",
00178             "There are still %n to-do editing windows open.",
00179             fPendingTodos);
00180 #endif
00181         return false;
00182     }
00183 
00184     return true;
00185 }
00186 
00187 void TodoWidget::postHotSync()
00188 {
00189     FUNCTIONSETUP;
00190 
00191     fTodoList.clear();
00192     showComponent();
00193 }
00194 
00195 void TodoWidget::hideComponent()
00196 {
00197     FUNCTIONSETUP;
00198     if ( fPendingTodos==0 )
00199     {
00200         fTodoList.clear();
00201         fListBox->clear();
00202         KPILOT_DELETE( fTodoDB );
00203     }
00204 }
00205 
00206 void TodoWidget::setupWidget()
00207 {
00208     FUNCTIONSETUP;
00209 
00210     QLabel *label;
00211     QGridLayout *grid = new QGridLayout(this, 6, 4, SPACING);
00212 
00213     fCatList = new QComboBox(this);
00214     grid->addWidget(fCatList, 0, 1);
00215     connect(fCatList, SIGNAL(activated(int)),
00216         this, SLOT(slotSetCategory(int)));
00217     QWhatsThis::add(fCatList,
00218         i18n("<qt>Select the category of to-dos to display here.</qt>"));
00219 
00220     label = new QLabel(i18n("Category:"), this);
00221     label->setBuddy(fCatList);
00222     grid->addWidget(label, 0, 0);
00223 
00224     fListBox = new TodoListView(this);
00225     fListBox->addColumn( i18n( "To-do Item" ) );
00226     fListBox->setAllColumnsShowFocus( TRUE );
00227     fListBox->setResizeMode( KListView::LastColumn );
00228     fListBox->setFullWidth( TRUE );
00229     fListBox->setItemsMovable( FALSE );
00230     fListBox->setItemsRenameable (TRUE);
00231     grid->addMultiCellWidget(fListBox, 1, 1, 0, 1);
00232     connect(fListBox, SIGNAL(selectionChanged(QListViewItem*)),
00233         this, SLOT(slotShowTodo(QListViewItem*)));
00234     connect(fListBox, SIGNAL(doubleClicked(QListViewItem*)),
00235         this, SLOT(slotEditRecord(QListViewItem*)));
00236     connect(fListBox, SIGNAL(returnPressed(QListViewItem*)),
00237         this, SLOT(slotEditRecord(QListViewItem*)));
00238     connect(fListBox, SIGNAL(itemChecked(QCheckListItem*, bool)),
00239         this, SLOT(slotItemChecked(QCheckListItem*, bool)));
00240     connect(fListBox, SIGNAL(itemRenamed(QListViewItem*, const QString &, int)),
00241         this, SLOT(slotItemRenamed(QListViewItem*, const QString &, int)));
00242     QWhatsThis::add(fListBox,
00243         i18n("<qt>This list displays all the to-dos "
00244             "in the selected category. Click on "
00245             "one to display it to the right.</qt>"));
00246 
00247     label = new QLabel(i18n("To-do info:"), this);
00248     grid->addWidget(label, 0, 2);
00249 
00250     // todo info text view
00251     fTodoInfo = new QTextView(this);
00252     grid->addMultiCellWidget(fTodoInfo, 1, 4, 2, 2);
00253 
00254     QPushButton *button;
00255     QString wt;
00256 
00257     fEditButton = new QPushButton(i18n("Edit Record..."), this);
00258     grid->addWidget(fEditButton, 2, 0);
00259     connect(fEditButton, SIGNAL(clicked()), this, SLOT(slotEditRecord()));
00260 
00261     wt = KPilotSettings::internalEditors() ?
00262         i18n("<qt>You can edit a to-do when it is selected.</qt>") :
00263         i18n("<qt><i>Editing is disabled by the 'internal editors' setting.</i></qt>");
00264     QWhatsThis::add(fEditButton,wt);
00265 
00266     button = new QPushButton(i18n("New Record..."), this);
00267     grid->addWidget(button, 2, 1);
00268     connect(button, SIGNAL(clicked()), this, SLOT(slotCreateNewRecord()));
00269     wt = KPilotSettings::internalEditors() ?
00270         i18n("<qt>Add a new to-do to the to-do list.</qt>") :
00271         i18n("<qt><i>Adding new to-dos is disabled by the 'internal editors' setting.</i></qt>");
00272     QWhatsThis::add(button, wt);
00273     button->setEnabled(KPilotSettings::internalEditors());
00274 
00275     fDeleteButton = new QPushButton(i18n("Delete Record"), this);
00276     grid->addWidget(fDeleteButton, 3, 0);
00277     connect(fDeleteButton, SIGNAL(clicked()),
00278         this, SLOT(slotDeleteRecord()));
00279     wt = KPilotSettings::internalEditors() ?
00280         i18n("<qt>Delete the selected to-do from the to-do list.</qt>") :
00281         i18n("<qt><i>Deleting is disabled by the 'internal editors' setting.</i></qt>") ;
00282     QWhatsThis::add(fDeleteButton,wt);
00283 }
00284 
00285 void TodoWidget::updateWidget()
00286 {
00287     FUNCTIONSETUP;
00288     if (!shown || !fTodoAppInfo ) return;
00289 
00290     int listIndex = 0;
00291 
00292     int currentCatID = findSelectedCategory(fCatList,
00293         fTodoAppInfo->categoryInfo());
00294 
00295     fListBox->clear();
00296     fTodoList.first();
00297 
00298 #ifdef DEBUG
00299     DEBUGKPILOT << fname << ": Adding records..." << endl;
00300 #endif
00301 
00302     PilotTodoEntry*todo;
00303     while (fTodoList.current())
00304     {
00305         todo=fTodoList.current();
00306         if ((currentCatID == -1) ||
00307             (todo->category() == currentCatID))
00308         {
00309             QString title = todo->getDescription();
00310 
00311             TodoCheckListItem*item=new TodoCheckListItem(fListBox, title,
00312                 listIndex, todo);
00313             item->setOn(todo->getComplete());
00314         }
00315         listIndex++;
00316         fTodoList.next();
00317     }
00318 
00319 #ifdef DEBUG
00320     DEBUGKPILOT << fname << ": " << listIndex << " records" << endl;
00321 #endif
00322 
00323     slotUpdateButtons();
00324 }
00325 
00326 
00327 
00328 /* slot */ void TodoWidget::slotUpdateButtons()
00329 {
00330     FUNCTIONSETUP;
00331 
00332     bool enabled = (fListBox->currentItem() != 0L);
00333 
00334     enabled &= KPilotSettings::internalEditors() ;
00335 
00336     fEditButton->setEnabled(enabled);
00337     fDeleteButton->setEnabled(enabled);
00338 }
00339 
00340 void TodoWidget::slotSetCategory(int)
00341 {
00342     FUNCTIONSETUP;
00343 
00344     updateWidget();
00345 }
00346 
00347 void TodoWidget::slotEditRecord()
00348 {
00349     slotEditRecord(fListBox->currentItem());
00350 }
00351 void TodoWidget::slotEditRecord(QListViewItem*item)
00352 {
00353     FUNCTIONSETUP;
00354     if (!shown) return;
00355 
00356     TodoCheckListItem*p = static_cast<TodoCheckListItem*>(item);
00357     if (!p) return;
00358     PilotTodoEntry *selectedRecord = (PilotTodoEntry *) p->rec();
00359 
00360     if (selectedRecord->id() == 0)
00361     {
00362         KMessageBox::error(0L,
00363             i18n("Cannot edit new records until "
00364                 "HotSynced with Pilot."),
00365             i18n("HotSync Required"));
00366         return;
00367     }
00368 
00369     TodoEditor *editor = new TodoEditor(selectedRecord,
00370         fTodoAppInfo->info(), this);
00371 
00372     connect(editor, SIGNAL(recordChangeComplete(PilotTodoEntry *)),
00373         this, SLOT(slotUpdateRecord(PilotTodoEntry *)));
00374     connect(editor, SIGNAL(cancelClicked()),
00375         this, SLOT(slotEditCancelled()));
00376     editor->show();
00377 
00378     fPendingTodos++;
00379 }
00380 
00381 void TodoWidget::slotCreateNewRecord()
00382 {
00383     FUNCTIONSETUP;
00384     if (!shown) return;
00385 
00386     // Response to bug 18072: Don't even try to
00387     // add records to an empty or unopened database,
00388     // since we don't have the DBInfo stuff to deal with it.
00389     //
00390     //
00391     PilotDatabase *myDB = new PilotLocalDatabase(dbPath(), CSL1("ToDoDB"));
00392 
00393     if (!myDB || !myDB->isOpen())
00394     {
00395 #ifdef DEBUG
00396         DEBUGKPILOT << fname
00397             << ": Tried to open "
00398             << dbPath()
00399             << "/ToDoDB"
00400             << " and got pointer @"
00401             << (void *) myDB
00402             << " with status "
00403             << ( myDB ? myDB->isOpen() : false )
00404             << endl;
00405 #endif
00406 
00407         KMessageBox::sorry(this,
00408             i18n("You cannot add to-dos to the to-do list "
00409                 "until you have done a HotSync at least once "
00410                 "to retrieve the database layout from your Pilot."),
00411             i18n("Cannot Add New To-do"));
00412 
00413         if (myDB)
00414             KPILOT_DELETE( myDB );
00415 
00416         return;
00417     }
00418 
00419     TodoEditor *editor = new TodoEditor(0L,
00420         fTodoAppInfo->info(), this);
00421 
00422     connect(editor, SIGNAL(recordChangeComplete(PilotTodoEntry *)),
00423         this, SLOT(slotAddRecord(PilotTodoEntry *)));
00424     connect(editor, SIGNAL(cancelClicked()),
00425         this, SLOT(slotEditCancelled()));
00426     editor->show();
00427 
00428     fPendingTodos++;
00429 }
00430 
00431 void TodoWidget::slotAddRecord(PilotTodoEntry * todo)
00432 {
00433     FUNCTIONSETUP;
00434     if ( !shown && fPendingTodos==0 ) return;
00435 
00436     int currentCatID = findSelectedCategory(fCatList,
00437         fTodoAppInfo->categoryInfo(), true);
00438 
00439 
00440     todo->PilotRecordBase::setCategory(currentCatID);
00441     fTodoList.append(todo);
00442     writeTodo(todo);
00443     // TODO: Just add the new record to the lists
00444     updateWidget();
00445 
00446     // k holds the item number of the todo just added.
00447     //
00448 //  int k = fListBox->count() - 1;
00449 //
00450 //  fListBox->setCurrentItem(k);    // Show the newest one
00451 //  fListBox->setBottomItem(k);
00452 
00453     fPendingTodos--;
00454     if ( !shown && fPendingTodos==0 ) hideComponent();
00455 }
00456 
00457 void TodoWidget::slotUpdateRecord(PilotTodoEntry * todo)
00458 {
00459     FUNCTIONSETUP;
00460     if ( !shown && fPendingTodos==0 ) return;
00461 
00462     writeTodo(todo);
00463     TodoCheckListItem* currentRecord = static_cast<TodoCheckListItem*>(fListBox->currentItem());
00464 
00465     // TODO: Just change the record
00466     updateWidget();
00467     fListBox->setCurrentItem(currentRecord);
00468 
00469     emit(recordChanged(todo));
00470 
00471     fPendingTodos--;
00472     if ( !shown && fPendingTodos==0 ) hideComponent();
00473 }
00474 
00475 void TodoWidget::slotEditCancelled()
00476 {
00477     FUNCTIONSETUP;
00478 
00479     fPendingTodos--;
00480     if ( !shown && fPendingTodos==0 ) hideComponent();
00481 }
00482 
00483 void TodoWidget::slotDeleteRecord()
00484 {
00485     FUNCTIONSETUP;
00486     if (!shown) return;
00487 
00488     TodoCheckListItem* p = static_cast<TodoCheckListItem*>(fListBox->currentItem());
00489     if (p == 0L) return;
00490 
00491     PilotTodoEntry *selectedRecord = (PilotTodoEntry *) p->rec();
00492 
00493     if (selectedRecord->id() == 0)
00494     {
00495         KMessageBox::error(this,
00496             i18n("New records cannot be deleted until "
00497                 "HotSynced with pilot."),
00498             i18n("HotSync Required"));
00499         return;
00500     }
00501 
00502     if (KMessageBox::questionYesNo(this,
00503             i18n("Delete currently selected record?"),
00504             i18n("Delete Record?"), KStdGuiItem::del(), KStdGuiItem::cancel()) == KMessageBox::No)
00505         return;
00506 
00507     selectedRecord->setDeleted(true);
00508     writeTodo(selectedRecord);
00509     emit(recordChanged(selectedRecord));
00510     showComponent();
00511 }
00512 
00513 
00514 
00515 void TodoWidget::slotShowTodo(QListViewItem*item)
00516 {
00517     FUNCTIONSETUP;
00518     if (!shown) return;
00519 
00520     TodoCheckListItem *p = dynamic_cast<TodoCheckListItem*>(item);
00521     if (!p) return;
00522     PilotTodoEntry *todo = (PilotTodoEntry *) p->rec();
00523 
00524 #ifdef DEBUG
00525     DEBUGKPILOT << fname << ": Showing "<< todo->getDescription()<<endl;
00526 #endif
00527 
00528     QString text(CSL1("<qt>"));
00529     text += todo->getTextRepresentation(Qt::RichText);
00530     text += CSL1("</qt>\n");
00531     fTodoInfo->setText(text);
00532 
00533     slotUpdateButtons();
00534 }
00535 
00536 
00537 
00538 void TodoWidget::writeTodo(PilotTodoEntry * which,
00539     PilotDatabase * todoDB)
00540 {
00541     FUNCTIONSETUP;
00542 
00543     // Open a database (myDB) only if needed,
00544     // i.e. only if the passed-in todoDB
00545     // isn't valid.
00546     //
00547     //
00548     PilotDatabase *myDB = todoDB;
00549     bool usemyDB = false;
00550 
00551     if (myDB == 0L || !myDB->isOpen())
00552     {
00553         myDB = new PilotLocalDatabase(dbPath(), CSL1("ToDoDB"));
00554         usemyDB = true;
00555     }
00556 
00557     // Still no valid todo database...
00558     //
00559     //
00560     if (!myDB->isOpen())
00561     {
00562 #ifdef DEBUG
00563         DEBUGKPILOT << fname << ": Todo database is not open" <<
00564             endl;
00565 #endif
00566         return;
00567     }
00568 
00569 
00570     // Do the actual work.
00571     PilotRecord *pilotRec = which->pack();
00572 
00573     myDB->writeRecord(pilotRec);
00574     markDBDirty(CSL1("ToDoDB"));
00575     KPILOT_DELETE(pilotRec);
00576 
00577 
00578     // Clean up in the case that we allocated our own DB.
00579     //
00580     //
00581     if (usemyDB)
00582     {
00583         KPILOT_DELETE(myDB);
00584     }
00585 }
00586 
00587 void TodoWidget::slotItemChecked(QCheckListItem*item, bool on)
00588 {
00589     TodoCheckListItem*p = static_cast<TodoCheckListItem*>(item);
00590     if (!p) return;
00591     PilotTodoEntry *selectedRecord = (PilotTodoEntry *) p->rec();
00592     if (!selectedRecord) return;
00593     selectedRecord->setComplete(on);
00594     slotShowTodo(item);
00595 }
00596 
00597 void TodoWidget::slotItemRenamed(QListViewItem*item, const QString &txt, int nr)
00598 {
00599     TodoCheckListItem*p = static_cast<TodoCheckListItem*>(item);
00600     if (!p) return;
00601     PilotTodoEntry *selectedRecord = (PilotTodoEntry *) p->rec();
00602     if (!selectedRecord) return;
00603     if (nr==0)
00604     {
00605         selectedRecord->setDescription(txt);
00606         slotShowTodo(item);
00607     }
00608 }