kpilot/kpilot

todoWidget.cc

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(*(fTodoAppInfo->info()), pilotRec);
00105             if (todo == 0L)
00106             {
00107                 kdWarning() << k_funcinfo
00108                     << ": Couldn't allocate record "
00109                     << currentRecord++
00110                     << endl;
00111                 break;
00112             }
00113             fTodoList.append(todo);
00114         }
00115         KPILOT_DELETE( pilotRec );
00116 
00117         currentRecord++;
00118     }
00119 
00120 #ifdef DEBUG
00121     DEBUGKPILOT << fname
00122         << ": Total " << currentRecord << " records" << endl;
00123 #endif
00124 
00125     return currentRecord;
00126 }
00127 
00128 void TodoWidget::showComponent()
00129 {
00130     FUNCTIONSETUP;
00131     if ( fPendingTodos>0 ) return;
00132 
00133 #ifdef DEBUG
00134     DEBUGKPILOT << fname
00135         << ": Reading from directory " << dbPath() << endl;
00136 #endif
00137 
00138     fTodoDB = new PilotLocalDatabase(dbPath(), CSL1("ToDoDB"));
00139 
00140     fTodoList.clear();
00141 
00142     if (fTodoDB->isOpen())
00143     {
00144         KPILOT_DELETE(fTodoAppInfo);
00145         fTodoAppInfo = new PilotToDoInfo(fTodoDB);
00146         populateCategories(fCatList, fTodoAppInfo->categoryInfo());
00147         getAllTodos(fTodoDB);
00148 
00149     }
00150     else
00151     {
00152         populateCategories(fCatList, 0L);
00153         kdWarning() << k_funcinfo
00154             << ": Could not open local TodoDB" << endl;
00155     }
00156 
00157     KPILOT_DELETE( fTodoDB );
00158 
00159     updateWidget();
00160 }
00161 
00162 /* virtual */ bool TodoWidget::preHotSync(QString &s)
00163 {
00164     FUNCTIONSETUP;
00165 
00166     if (fPendingTodos)
00167     {
00168 #ifdef DEBUG
00169         DEBUGKPILOT << fname
00170             << ": fPendingTodo="
00171             << fPendingTodos
00172             << endl;
00173 #endif
00174 
00175 #if KDE_VERSION<220
00176         s = i18n("There are still %1 to-do editing windows open.")
00177             .arg(QString::number(fPendingTodos));
00178 #else
00179         s = i18n("There is still a to-do editing window open.",
00180             "There are still %n to-do editing windows open.",
00181             fPendingTodos);
00182 #endif
00183         return false;
00184     }
00185 
00186     return true;
00187 }
00188 
00189 void TodoWidget::postHotSync()
00190 {
00191     FUNCTIONSETUP;
00192 
00193     fTodoList.clear();
00194     showComponent();
00195 }
00196 
00197 void TodoWidget::hideComponent()
00198 {
00199     FUNCTIONSETUP;
00200     if ( fPendingTodos==0 )
00201     {
00202         fTodoList.clear();
00203         fListBox->clear();
00204         KPILOT_DELETE( fTodoDB );
00205     }
00206 }
00207 
00208 void TodoWidget::setupWidget()
00209 {
00210     FUNCTIONSETUP;
00211 
00212     QLabel *label;
00213     QGridLayout *grid = new QGridLayout(this, 6, 4, SPACING);
00214 
00215     fCatList = new QComboBox(this);
00216     grid->addWidget(fCatList, 0, 1);
00217     connect(fCatList, SIGNAL(activated(int)),
00218         this, SLOT(slotSetCategory(int)));
00219     QWhatsThis::add(fCatList,
00220         i18n("<qt>Select the category of to-dos to display here.</qt>"));
00221 
00222     label = new QLabel(i18n("Category:"), this);
00223     label->setBuddy(fCatList);
00224     grid->addWidget(label, 0, 0);
00225 
00226     fListBox = new TodoListView(this);
00227     fListBox->addColumn( i18n( "To-do Item" ) );
00228     fListBox->setAllColumnsShowFocus( TRUE );
00229     fListBox->setResizeMode( KListView::LastColumn );
00230     fListBox->setFullWidth( TRUE );
00231     fListBox->setItemsMovable( FALSE );
00232     fListBox->setItemsRenameable (TRUE);
00233     grid->addMultiCellWidget(fListBox, 1, 1, 0, 1);
00234     connect(fListBox, SIGNAL(selectionChanged(QListViewItem*)),
00235         this, SLOT(slotShowTodo(QListViewItem*)));
00236     connect(fListBox, SIGNAL(doubleClicked(QListViewItem*)),
00237         this, SLOT(slotEditRecord(QListViewItem*)));
00238     connect(fListBox, SIGNAL(returnPressed(QListViewItem*)),
00239         this, SLOT(slotEditRecord(QListViewItem*)));
00240     connect(fListBox, SIGNAL(itemChecked(QCheckListItem*, bool)),
00241         this, SLOT(slotItemChecked(QCheckListItem*, bool)));
00242     connect(fListBox, SIGNAL(itemRenamed(QListViewItem*, const QString &, int)),
00243         this, SLOT(slotItemRenamed(QListViewItem*, const QString &, int)));
00244     QWhatsThis::add(fListBox,
00245         i18n("<qt>This list displays all the to-dos "
00246             "in the selected category. Click on "
00247             "one to display it to the right.</qt>"));
00248 
00249     label = new QLabel(i18n("To-do info:"), this);
00250     grid->addWidget(label, 0, 2);
00251 
00252     // todo info text view
00253     fTodoInfo = new QTextView(this);
00254     grid->addMultiCellWidget(fTodoInfo, 1, 4, 2, 2);
00255 
00256     QPushButton *button;
00257     QString wt;
00258 
00259     fEditButton = new QPushButton(i18n("Edit Record..."), this);
00260     grid->addWidget(fEditButton, 2, 0);
00261     connect(fEditButton, SIGNAL(clicked()), this, SLOT(slotEditRecord()));
00262 
00263     wt = KPilotSettings::internalEditors() ?
00264         i18n("<qt>You can edit a to-do when it is selected.</qt>") :
00265         i18n("<qt><i>Editing is disabled by the 'internal editors' setting.</i></qt>");
00266     QWhatsThis::add(fEditButton,wt);
00267 
00268     button = new QPushButton(i18n("New Record..."), this);
00269     grid->addWidget(button, 2, 1);
00270     connect(button, SIGNAL(clicked()), this, SLOT(slotCreateNewRecord()));
00271     wt = KPilotSettings::internalEditors() ?
00272         i18n("<qt>Add a new to-do to the to-do list.</qt>") :
00273         i18n("<qt><i>Adding new to-dos is disabled by the 'internal editors' setting.</i></qt>");
00274     QWhatsThis::add(button, wt);
00275     button->setEnabled(KPilotSettings::internalEditors());
00276 
00277     fDeleteButton = new QPushButton(i18n("Delete Record"), this);
00278     grid->addWidget(fDeleteButton, 3, 0);
00279     connect(fDeleteButton, SIGNAL(clicked()),
00280         this, SLOT(slotDeleteRecord()));
00281     wt = KPilotSettings::internalEditors() ?
00282         i18n("<qt>Delete the selected to-do from the to-do list.</qt>") :
00283         i18n("<qt><i>Deleting is disabled by the 'internal editors' setting.</i></qt>") ;
00284     QWhatsThis::add(fDeleteButton,wt);
00285 }
00286 
00287 void TodoWidget::updateWidget()
00288 {
00289     FUNCTIONSETUP;
00290     if (!shown || !fTodoAppInfo ) return;
00291 
00292     int listIndex = 0;
00293 
00294     int currentCatID = findSelectedCategory(fCatList,
00295         fTodoAppInfo->categoryInfo());
00296 
00297     fListBox->clear();
00298     fTodoList.first();
00299 
00300 #ifdef DEBUG
00301     DEBUGKPILOT << fname << ": Adding records..." << endl;
00302 #endif
00303 
00304     PilotTodoEntry*todo;
00305     while (fTodoList.current())
00306     {
00307         todo=fTodoList.current();
00308         if ((currentCatID == -1) ||
00309             (todo->category() == currentCatID))
00310         {
00311             QString title = todo->getDescription();
00312 
00313             TodoCheckListItem*item=new TodoCheckListItem(fListBox, title,
00314                 listIndex, todo);
00315             item->setOn(todo->getComplete());
00316         }
00317         listIndex++;
00318         fTodoList.next();
00319     }
00320 
00321 #ifdef DEBUG
00322     DEBUGKPILOT << fname << ": " << listIndex << " records" << endl;
00323 #endif
00324 
00325     slotUpdateButtons();
00326 }
00327 
00328 
00329 
00330 /* slot */ void TodoWidget::slotUpdateButtons()
00331 {
00332     FUNCTIONSETUP;
00333 
00334     bool enabled = (fListBox->currentItem() != 0L);
00335 
00336     enabled &= KPilotSettings::internalEditors() ;
00337 
00338     fEditButton->setEnabled(enabled);
00339     fDeleteButton->setEnabled(enabled);
00340 }
00341 
00342 void TodoWidget::slotSetCategory(int)
00343 {
00344     FUNCTIONSETUP;
00345 
00346     updateWidget();
00347 }
00348 
00349 void TodoWidget::slotEditRecord()
00350 {
00351     slotEditRecord(fListBox->currentItem());
00352 }
00353 void TodoWidget::slotEditRecord(QListViewItem*item)
00354 {
00355     FUNCTIONSETUP;
00356     if (!shown) return;
00357 
00358     TodoCheckListItem*p = static_cast<TodoCheckListItem*>(item);
00359     if (!p) return;
00360     PilotTodoEntry *selectedRecord = (PilotTodoEntry *) p->rec();
00361 
00362     if (selectedRecord->id() == 0)
00363     {
00364         KMessageBox::error(0L,
00365             i18n("Cannot edit new records until "
00366                 "HotSynced with Pilot."),
00367             i18n("HotSync Required"));
00368         return;
00369     }
00370 
00371     TodoEditor *editor = new TodoEditor(selectedRecord,
00372         fTodoAppInfo->info(), this);
00373 
00374     connect(editor, SIGNAL(recordChangeComplete(PilotTodoEntry *)),
00375         this, SLOT(slotUpdateRecord(PilotTodoEntry *)));
00376     connect(editor, SIGNAL(cancelClicked()),
00377         this, SLOT(slotEditCancelled()));
00378     editor->show();
00379 
00380     fPendingTodos++;
00381 }
00382 
00383 void TodoWidget::slotCreateNewRecord()
00384 {
00385     FUNCTIONSETUP;
00386     if (!shown) return;
00387 
00388     // Response to bug 18072: Don't even try to
00389     // add records to an empty or unopened database,
00390     // since we don't have the DBInfo stuff to deal with it.
00391     //
00392     //
00393     PilotDatabase *myDB = new PilotLocalDatabase(dbPath(), CSL1("ToDoDB"));
00394 
00395     if (!myDB || !myDB->isOpen())
00396     {
00397 #ifdef DEBUG
00398         DEBUGKPILOT << fname
00399             << ": Tried to open "
00400             << dbPath()
00401             << "/ToDoDB"
00402             << " and got pointer @"
00403             << (void *) myDB
00404             << " with status "
00405             << ( myDB ? myDB->isOpen() : false )
00406             << endl;
00407 #endif
00408 
00409         KMessageBox::sorry(this,
00410             i18n("You cannot add to-dos to the to-do list "
00411                 "until you have done a HotSync at least once "
00412                 "to retrieve the database layout from your Pilot."),
00413             i18n("Cannot Add New To-do"));
00414 
00415         if (myDB)
00416             KPILOT_DELETE( myDB );
00417 
00418         return;
00419     }
00420 
00421     TodoEditor *editor = new TodoEditor(0L,
00422         fTodoAppInfo->info(), this);
00423 
00424     connect(editor, SIGNAL(recordChangeComplete(PilotTodoEntry *)),
00425         this, SLOT(slotAddRecord(PilotTodoEntry *)));
00426     connect(editor, SIGNAL(cancelClicked()),
00427         this, SLOT(slotEditCancelled()));
00428     editor->show();
00429 
00430     fPendingTodos++;
00431 }
00432 
00433 void TodoWidget::slotAddRecord(PilotTodoEntry * todo)
00434 {
00435     FUNCTIONSETUP;
00436     if ( !shown && fPendingTodos==0 ) return;
00437 
00438     int currentCatID = findSelectedCategory(fCatList,
00439         fTodoAppInfo->categoryInfo(), true);
00440 
00441 
00442     todo->PilotRecordBase::setCategory(currentCatID);
00443     fTodoList.append(todo);
00444     writeTodo(todo);
00445     // TODO: Just add the new record to the lists
00446     updateWidget();
00447 
00448     // k holds the item number of the todo just added.
00449     //
00450 //  int k = fListBox->count() - 1;
00451 //
00452 //  fListBox->setCurrentItem(k);    // Show the newest one
00453 //  fListBox->setBottomItem(k);
00454 
00455     fPendingTodos--;
00456     if ( !shown && fPendingTodos==0 ) hideComponent();
00457 }
00458 
00459 void TodoWidget::slotUpdateRecord(PilotTodoEntry * todo)
00460 {
00461     FUNCTIONSETUP;
00462     if ( !shown && fPendingTodos==0 ) return;
00463 
00464     writeTodo(todo);
00465     TodoCheckListItem* currentRecord = static_cast<TodoCheckListItem*>(fListBox->currentItem());
00466 
00467     // TODO: Just change the record
00468     updateWidget();
00469     fListBox->setCurrentItem(currentRecord);
00470 
00471     emit(recordChanged(todo));
00472 
00473     fPendingTodos--;
00474     if ( !shown && fPendingTodos==0 ) hideComponent();
00475 }
00476 
00477 void TodoWidget::slotEditCancelled()
00478 {
00479     FUNCTIONSETUP;
00480 
00481     fPendingTodos--;
00482     if ( !shown && fPendingTodos==0 ) hideComponent();
00483 }
00484 
00485 void TodoWidget::slotDeleteRecord()
00486 {
00487     FUNCTIONSETUP;
00488     if (!shown) return;
00489 
00490     TodoCheckListItem* p = static_cast<TodoCheckListItem*>(fListBox->currentItem());
00491     if (p == 0L) return;
00492 
00493     PilotTodoEntry *selectedRecord = (PilotTodoEntry *) p->rec();
00494 
00495     if (selectedRecord->id() == 0)
00496     {
00497         KMessageBox::error(this,
00498             i18n("New records cannot be deleted until "
00499                 "HotSynced with pilot."),
00500             i18n("HotSync Required"));
00501         return;
00502     }
00503 
00504     if (KMessageBox::questionYesNo(this,
00505             i18n("Delete currently selected record?"),
00506             i18n("Delete Record?"), KStdGuiItem::del(), KStdGuiItem::cancel()) == KMessageBox::No)
00507         return;
00508 
00509     selectedRecord->setDeleted(true);
00510     writeTodo(selectedRecord);
00511     emit(recordChanged(selectedRecord));
00512     showComponent();
00513 }
00514 
00515 
00516 
00517 void TodoWidget::slotShowTodo(QListViewItem*item)
00518 {
00519     FUNCTIONSETUP;
00520     if (!shown) return;
00521 
00522     TodoCheckListItem *p = dynamic_cast<TodoCheckListItem*>(item);
00523     if (!p) return;
00524     PilotTodoEntry *todo = (PilotTodoEntry *) p->rec();
00525 
00526 #ifdef DEBUG
00527     DEBUGKPILOT << fname << ": Showing "<< todo->getDescription()<<endl;
00528 #endif
00529 
00530     QString text(CSL1("<qt>"));
00531     text += todo->getTextRepresentation(true);
00532     text += CSL1("</qt>\n");
00533     fTodoInfo->setText(text);
00534 
00535     slotUpdateButtons();
00536 }
00537 
00538 
00539 
00540 void TodoWidget::writeTodo(PilotTodoEntry * which,
00541     PilotDatabase * todoDB)
00542 {
00543     FUNCTIONSETUP;
00544 
00545     // Open a database (myDB) only if needed,
00546     // i.e. only if the passed-in todoDB
00547     // isn't valid.
00548     //
00549     //
00550     PilotDatabase *myDB = todoDB;
00551     bool usemyDB = false;
00552 
00553     if (myDB == 0L || !myDB->isOpen())
00554     {
00555         myDB = new PilotLocalDatabase(dbPath(), CSL1("ToDoDB"));
00556         usemyDB = true;
00557     }
00558 
00559     // Still no valid todo database...
00560     //
00561     //
00562     if (!myDB->isOpen())
00563     {
00564 #ifdef DEBUG
00565         DEBUGKPILOT << fname << ": Todo database is not open" <<
00566             endl;
00567 #endif
00568         return;
00569     }
00570 
00571 
00572     // Do the actual work.
00573     PilotRecord *pilotRec = which->pack();
00574 
00575     myDB->writeRecord(pilotRec);
00576     markDBDirty(CSL1("ToDoDB"));
00577     KPILOT_DELETE(pilotRec);
00578 
00579 
00580     // Clean up in the case that we allocated our own DB.
00581     //
00582     //
00583     if (usemyDB)
00584     {
00585         KPILOT_DELETE(myDB);
00586     }
00587 }
00588 
00589 void TodoWidget::slotItemChecked(QCheckListItem*item, bool on)
00590 {
00591     TodoCheckListItem*p = static_cast<TodoCheckListItem*>(item);
00592     if (!p) return;
00593     PilotTodoEntry *selectedRecord = (PilotTodoEntry *) p->rec();
00594     if (!selectedRecord) return;
00595     selectedRecord->setComplete(on);
00596     slotShowTodo(item);
00597 }
00598 
00599 void TodoWidget::slotItemRenamed(QListViewItem*item, const QString &txt, int nr)
00600 {
00601     TodoCheckListItem*p = static_cast<TodoCheckListItem*>(item);
00602     if (!p) return;
00603     PilotTodoEntry *selectedRecord = (PilotTodoEntry *) p->rec();
00604     if (!selectedRecord) return;
00605     if (nr==0)
00606     {
00607         selectedRecord->setDescription(txt);
00608         slotShowTodo(item);
00609     }
00610 }
KDE Home | KDE Accessibility Home | Description of Access Keys