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