kpilot Library API Documentation

memoWidget.cc

00001 /* memoWidget.cc            KPilot
00002 **
00003 ** Copyright (C) 1998-2001 by Dan Pilone
00004 **
00005 ** This is the memo-viewing widget (internal conduit) used by KPilot.
00006 */
00007 
00008 /*
00009 ** This program is free software; you can redistribute it and/or modify
00010 ** it under the terms of the GNU General Public License as published by
00011 ** the Free Software Foundation; either version 2 of the License, or
00012 ** (at your option) any later version.
00013 **
00014 ** This program is distributed in the hope that it will be useful,
00015 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00017 ** GNU General Public License for more details.
00018 **
00019 ** You should have received a copy of the GNU General Public License
00020 ** along with this program in a file called COPYING; if not, write to
00021 ** the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00022 ** MA 02111-1307, USA.
00023 */
00024 
00025 /*
00026 ** Bug reports and questions can be sent to kde-pim@kde.org
00027 */
00028 static const char *memowidget_id =
00029     "$Id: memoWidget.cc,v 1.61 2003/10/13 13:58:19 kainhofe Exp $";
00030 
00031 #include "options.h"
00032 
00033 #include <time.h>
00034 
00035 #include <pi-macros.h>
00036 #include <pi-dlp.h>
00037 
00038 #include <qdir.h>
00039 #include <qptrlist.h>
00040 #include <qlistbox.h>
00041 #include <qfile.h>
00042 #include <qpushbutton.h>
00043 #include <qlayout.h>
00044 #include <qdom.h>
00045 #include <qtextstream.h>
00046 #include <qwhatsthis.h>
00047 #include <qlabel.h>
00048 #include <qtextcodec.h>
00049 
00050 #include <kapplication.h>
00051 #include <kmessagebox.h>
00052 #include <kfiledialog.h>
00053 
00054 #include "kpilot.h"
00055 #include "kpilotConfig.h"
00056 #include "listItems.h"
00057 #include "pilotLocalDatabase.h"
00058 #include "pilotMemo.h"
00059 
00060 #include "memoWidget.moc"
00061 
00062 
00063 // This constant (0xffff) appears all over the place (mostly in
00064 // ::initialize(), but elsewhere as well. It seems to be inherited
00065 // from the pilot-link library.
00066 //
00067 // I've replaced instances of the constant with this #define
00068 //
00069 //
00070 #define PILOT_BUFFER_SIZE   (0xffff)
00071 
00072 
00073 
00074 MemoWidget::MemoWidget(QWidget * parent,
00075     const QString & path) :
00076     PilotComponent(parent, "component_memo", path),
00077     fTextWidget(0L),
00078     lastSelectedMemo(-1)
00079 {
00080     FUNCTIONSETUP;
00081 
00082     setGeometry(0, 0,
00083         parent->geometry().width(), parent->geometry().height());
00084     setupWidget();
00085     fMemoList.setAutoDelete(true);
00086     slotUpdateButtons();
00087 
00088 #if 0
00089     connect(fTextWidget, SIGNAL(textChanged()),
00090         this, SLOT(slotTextChanged()));
00091 #endif
00092 
00093     /* NOTREACHED */
00094     (void) memowidget_id;
00095 }
00096 
00097 MemoWidget::~MemoWidget()
00098 {
00099     FUNCTIONSETUP;
00100     saveChangedMemo();
00101 }
00102 
00103 
00104 // void MemoWidget::initializeMemos(PilotDatabase *memoDB)
00105 //
00106 // Reads all the memos from the local database and places them
00107 // in the selection screen.
00108 //
00109 
00110 void MemoWidget::initializeMemos(PilotDatabase * memoDB)
00111 {
00112     FUNCTIONSETUP;
00113 
00114 
00115     // ShowSecrets tells us to also list memos with an attribute of "Secret"
00116     // or "Private"
00117     //
00118     bool showSecrets = KPilotConfig::getConfig().getShowSecrets();
00119 
00120     fMemoList.clear();
00121 
00122 
00123     int currentRecord = 0;
00124     PilotRecord *pilotRec;
00125     PilotMemo *memo;
00126 
00127     while ((pilotRec = memoDB->readRecordByIndex(currentRecord)) != NULL)
00128     {
00129         if (!pilotRec->isDeleted())
00130         {
00131             if ((!pilotRec->isSecret()) || showSecrets)
00132             {
00133                 memo = new PilotMemo(pilotRec);
00134                 fMemoList.append(memo);
00135 
00136 #ifdef DEBUG
00137                 DEBUGKPILOT << fname <<
00138                     ": Added memo "
00139                     << currentRecord << endl;
00140 #endif
00141             }
00142             else
00143             {
00144 #ifdef DEBUG
00145                 DEBUGKPILOT << fname <<
00146                     ": Skipped secret record " <<
00147                     currentRecord << endl;
00148 #endif
00149             }
00150         }
00151         else
00152         {
00153 #ifdef DEBUG
00154             DEBUGKPILOT << fname <<
00155                 ": Skipped deleted record " <<
00156                 currentRecord << endl;
00157 #endif
00158         }
00159 
00160         delete pilotRec;
00161 
00162         currentRecord++;
00163     }
00164 }
00165 
00166 
00167 void MemoWidget::showComponent()
00168 {
00169     FUNCTIONSETUP;
00170     if (!shown) return;
00171 
00172     // Get the local database - assume the call may fail and return
00173     // NULL, or the database object may be returned but unopened.
00174     //
00175     //
00176     PilotLocalDatabase *memoDB =
00177         new PilotLocalDatabase(dbPath(), CSL1("MemoDB"));
00178     if (memoDB == NULL || !memoDB->isDBOpen())
00179     {
00180         kdWarning() << k_funcinfo <<
00181             ": Can't open local database MemoDB\n";
00182 
00183         populateCategories(fCatList, 0L);
00184         updateWidget();
00185         return;
00186     }
00187 
00188     // Normal case: there is a database so we can read it
00189     // and determine all the categories.
00190     //
00191     int appLen = memoDB->appInfoSize();
00192 
00193 #ifdef DEBUG
00194     DEBUGKPILOT << fname << ": Got appInfoLen " << appLen << endl;
00195 #endif
00196 
00197     unpack_MemoAppInfo(&fMemoAppInfo,
00198         (unsigned char *) memoDB->appInfo(), appLen);
00199 
00200 #ifdef DEBUG
00201     DEBUGKPILOT << fname << ": Unpacked app info." << endl;
00202 
00203     for (int i = 0; i < 15; i++)
00204     {
00205         DEBUGKPILOT << fname
00206             << ": Category #"
00207             << i
00208             << " has ID "
00209             << (int) fMemoAppInfo.category.ID[i]
00210             << " and name "
00211             << (fMemoAppInfo.category.name[i][0] ? "*" : "-")
00212             << fMemoAppInfo.category.name[i] << endl;
00213     }
00214 #endif
00215 
00216     populateCategories(fCatList, &fMemoAppInfo.category);
00217 
00218 #ifdef DEBUG
00219     DEBUGKPILOT << fname << ": Populated categories" << endl;
00220 #endif
00221 
00222     initializeMemos(memoDB);
00223 
00224 #ifdef DEBUG
00225     DEBUGKPILOT << fname << ": Finished initializing" << endl;
00226 #endif
00227 
00228     KPILOT_DELETE( memoDB );
00229 
00230     updateWidget();
00231 }
00232 
00233 void MemoWidget::hideComponent()
00234 {
00235     FUNCTIONSETUP;
00236     saveChangedMemo();
00237     fCatList->clear();
00238     fTextWidget->clear();
00239     fMemoList.clear();
00240     fListBox->clear();
00241     lastSelectedMemo = -1;
00242 }
00243 
00244 void MemoWidget::postHotSync()
00245 {
00246     FUNCTIONSETUP;
00247     fMemoList.clear();
00248     showComponent();
00249 }
00250 
00251 
00252 // void MemoWidget::setupWidget()
00253 //
00254 // Setup all the GUI components by allocating them.
00255 //
00256 //
00257 void MemoWidget::setupWidget()
00258 {
00259     FUNCTIONSETUP;
00260 
00261     QLabel *label = NULL;
00262     QPushButton *button = NULL;
00263     QGridLayout *grid = new QGridLayout(this, 5, 4, SPACING);
00264 
00265     fCatList = new QComboBox(this);
00266     grid->addWidget(fCatList, 0, 1);
00267     connect(fCatList, SIGNAL(activated(int)),
00268         this, SLOT(slotSetCategory(int)));
00269     QWhatsThis::add(fCatList,
00270         i18n("Select the category of addresses\n"
00271             "to display here."));
00272 
00273     (void) i18n("Memos:");
00274     label = new QLabel(i18n("Category:"), this);
00275     label->setBuddy(fCatList);
00276     grid->addWidget(label, 0, 0);
00277 
00278     fListBox = new QListBox(this);
00279     grid->addMultiCellWidget(fListBox, 1, 1, 0, 1);
00280     connect(fListBox, SIGNAL(highlighted(int)),
00281         this, SLOT(slotShowMemo(int)));
00282     connect(fListBox, SIGNAL(selectionChanged()),
00283         this,SLOT(slotUpdateButtons()));
00284     QWhatsThis::add(fListBox,
00285         i18n("This list displays all the memos\n"
00286             "in the selected category. Click on\n"
00287             "one to display it to the right."));
00288 
00289     label = new QLabel(i18n("Memo text:"), this);
00290     grid->addWidget(label, 0, 2);
00291 
00292     fTextWidget = new KTextEdit(this, "textArea");
00293     fTextWidget->setWordWrap(KTextEdit::WidgetWidth);
00294     fTextWidget->setTextFormat(Qt::PlainText);
00295     grid->addMultiCellWidget(fTextWidget, 1, 4, 2, 2);
00296     QWhatsThis::add(fTextWidget,
00297         i18n("The text of the selected memo appears here."));
00298 
00299     button = new QPushButton(i18n("Import Memo..."), this);
00300     grid->addWidget(button, 2, 0);
00301     connect(button, SIGNAL(clicked()), this, SLOT(slotImportMemo()));
00302     QWhatsThis::add(button,
00303         i18n
00304         ("Read a text file and add it to the Pilot's memo database."));
00305 
00306     fExportButton = new QPushButton(i18n("Export Memo..."), this);
00307     grid->addWidget(fExportButton, 2, 1);
00308     connect(fExportButton, SIGNAL(clicked()), this,
00309         SLOT(slotExportMemo()));
00310     QWhatsThis::add(fExportButton,
00311         i18n("Write the selected memo to a file."));
00312 
00313     fDeleteButton = new QPushButton(i18n("Delete Memo"), this);
00314     grid->addWidget(fDeleteButton, 3, 0);
00315     connect(fDeleteButton, SIGNAL(clicked()), this,
00316         SLOT(slotDeleteMemo()));
00317     QWhatsThis::add(fDeleteButton, i18n("Delete the selected memo."));
00318 }
00319 
00320 void MemoWidget::slotUpdateButtons()
00321 {
00322     FUNCTIONSETUP;
00323 
00324     bool highlight = false;
00325 
00326     if ((fListBox->currentItem() != -1) &&
00327         (fListBox->isSelected(fListBox->currentItem())))
00328             highlight=true;
00329 
00330 #ifdef DEBUG
00331     DEBUGKPILOT << fname << ": Selected items " << highlight << endl;
00332 #endif
00333 
00334     if (fExportButton)
00335     {
00336         fExportButton->setEnabled(highlight);
00337     }
00338     if (fDeleteButton)
00339     {
00340         fDeleteButton->setEnabled(highlight);
00341     }
00342 }
00343 
00344 void MemoWidget::slotSetCategory(int)
00345 {
00346     FUNCTIONSETUP;
00347     updateWidget();
00348 }
00349 
00350 void MemoWidget::slotDeleteMemo()
00351 {
00352     FUNCTIONSETUP;
00353     if (!shown) return;
00354 
00355     int item = fListBox->currentItem();
00356 
00357     if (item == -1)
00358     {
00359 #ifdef DEBUG
00360         DEBUGKPILOT << fname << ": No current item selected\n";
00361 #endif
00362         return;
00363     }
00364 
00365     PilotListItem *p = (PilotListItem *) fListBox->item(item);
00366     PilotMemo *selectedMemo = (PilotMemo *) p->rec();
00367 
00368     if (selectedMemo->id() == 0x0)
00369     {
00370         // QADE: Why is this? What prevents us from deleting
00371         // a "new" memo, ie. one we've imported, before *ever*
00372         // sending it to the Pilot?
00373         //
00374         //
00375         kdWarning() << k_funcinfo <<
00376             ": Refusing to delete new memo.\n";
00377 
00378         KMessageBox::error(this,
00379             i18n("New memo cannot be deleted until "
00380                 "HotSynced with pilot."),
00381             i18n("HotSync Required"));
00382         return;
00383     }
00384 
00385 
00386     if (KMessageBox::questionYesNo(this,
00387             i18n("Delete currently selected memo?"),
00388             i18n("Delete Memo?")) == KMessageBox::No)
00389     {
00390 #ifdef DEBUG
00391         DEBUGKPILOT << fname <<
00392             ": User decided not to delete memo.\n";
00393 #endif
00394         return;
00395     }
00396 
00397     selectedMemo->makeDeleted();
00398     writeMemo(selectedMemo);
00399     fMemoList.remove(selectedMemo);
00400     delete p;
00401 }
00402 
00403 
00404 void MemoWidget::updateWidget()
00405 {
00406     FUNCTIONSETUP;
00407     if (!shown) return;
00408 
00409     if (fCatList->currentItem() == -1)
00410     {
00411 #ifdef DEBUG
00412         DEBUGKPILOT << fname << ": No category selected.\n";
00413 #endif
00414         return;
00415     }
00416 
00417     int listIndex = 0;
00418     int currentCatID = findSelectedCategory(fCatList,
00419         &(fMemoAppInfo.category), false);
00420 
00421 
00422     fListBox->clear();
00423     fMemoList.first();
00424 
00425 
00426     // Iterate through all the memos and insert each memo
00427     // only if the category of the memo matches the selected category
00428     // (using -1 to mean "All")
00429     //
00430     //
00431     while (fMemoList.current())
00432     {
00433         if ((fMemoList.current()->getCat() == currentCatID) ||
00434             (currentCatID == -1))
00435         {
00436             PilotListItem *p =
00437                 new PilotListItem(fMemoList.current()->
00438                 shortTitle(),
00439                 listIndex,
00440                 fMemoList.current());
00441 
00442             // List will delete the title of the memo,
00443             // so there's no memory leak here.
00444             //
00445             //
00446             fListBox->insertItem(p);
00447 
00448 #ifdef DEBUG
00449             DEBUGKPILOT << fname << ": Added memo "
00450                 << fMemoList.current()->getTitle() << endl;
00451 #endif
00452         }
00453         else
00454         {
00455 #ifdef DEBUG
00456             DEBUGKPILOT << fname << ": Skipped memo "
00457                 << fMemoList.current()->getTitle() << endl;
00458 #endif
00459         }
00460 
00461         listIndex++;
00462         fMemoList.next();
00463     }
00464 
00465     fTextWidget->clear();
00466 
00467     slotUpdateButtons();
00468 
00469     lastSelectedMemo=-1;
00470 }
00471 
00472 void MemoWidget::slotShowMemo(int which)
00473 {
00474     FUNCTIONSETUP;
00475     if ( which == -1 ) return;
00476     if (!shown) return;
00477 
00478     slotUpdateButtons();
00479     if ( !fListBox->isSelected(which) )
00480     {
00481         // Handle unselecting a memo. This is easy.
00482         fTextWidget->blockSignals(true);
00483         fTextWidget->clear();
00484         fTextWidget->blockSignals(false);
00485         return;
00486     }
00487 
00488 
00489 #ifdef DEBUG
00490     DEBUGKPILOT << fname << ": Displaying memo " << which << endl;
00491 #endif
00492     fTextWidget->blockSignals(true);
00493     PilotListItem *p = (PilotListItem *) fListBox->item(which);
00494     PilotMemo *theMemo = (PilotMemo *) p->rec();
00495     fTextWidget->setText(theMemo->text());
00496     fTextWidget->blockSignals(false);
00497 }
00498 
00499 void MemoWidget::writeMemo(PilotMemo * which)
00500 {
00501     FUNCTIONSETUP;
00502     if (!shown) return;
00503 
00504     PilotDatabase *memoDB = new PilotLocalDatabase(dbPath(), CSL1("MemoDB"));
00505     PilotRecord *pilotRec = which->pack();
00506 
00507     memoDB->writeRecord(pilotRec);
00508     markDBDirty("MemoDB");
00509     KPILOT_DELETE( pilotRec );
00510     KPILOT_DELETE( memoDB );
00511 }
00512 
00513 void MemoWidget::saveChangedMemo()
00514 {
00515     FUNCTIONSETUP;
00516     if (!shown) return;
00517 
00518     if (-1 == lastSelectedMemo) return;
00519     if (!fTextWidget->isModified()) return;
00520 
00521 #ifdef DEBUG
00522     DEBUGKPILOT << fname
00523         << ": Saving changed memo " << lastSelectedMemo << endl;
00524 #endif
00525 
00526     PilotListItem *p =
00527         (PilotListItem *) fListBox->item(lastSelectedMemo);
00528     PilotMemo *currentMemo = (PilotMemo *) p->rec();
00529 
00530     currentMemo->setText(PilotAppCategory::codec()->
00531         fromUnicode(fTextWidget->text()));
00532     writeMemo(currentMemo);
00533 }
00534 
00535 /* virtual */ bool MemoWidget::preHotSync(QString &)
00536 {
00537     FUNCTIONSETUP;
00538     saveChangedMemo();
00539     return true;
00540 }
00541 
00542 void MemoWidget::slotImportMemo()
00543 {
00544     FUNCTIONSETUP;
00545     if (!shown) return;
00546 
00547     int i = 0;
00548     int nextChar;
00549     int currentCatID = findSelectedCategory(fCatList,
00550         &(fMemoAppInfo.category), true);
00551 
00552     QString fileName = KFileDialog::getOpenFileName();
00553 
00554     if (!fileName.isEmpty())
00555     {
00556         QFile importFile(fileName);
00557 
00558         if (importFile.open(IO_ReadOnly) == FALSE)
00559         {
00560             // show error!
00561             return;
00562         }
00563         char *text = new char[(int) MemoWidget::MAX_MEMO_LEN];
00564 
00565         for (i = 0;
00566             (i < (MemoWidget::MAX_MEMO_LEN - 1))
00567             && ((nextChar = importFile.getch()) != -1); i++)
00568             text[i] = nextChar;
00569         text[i] = 0;
00570         PilotMemo *aMemo = new PilotMemo(text, 0, 0, currentCatID);
00571 
00572         fMemoList.append(aMemo);
00573         writeMemo(aMemo);
00574         updateWidget();
00575         delete[]text;
00576     }
00577 }
00578 
00579 void MemoWidget::slotExportMemo()
00580 {
00581     FUNCTIONSETUP;
00582     if (!shown) return;
00583 
00584     int index = fListBox->numRows();
00585     if (index == 0)
00586         return;
00587 
00588     QString data;
00589 
00590     const QString filter = CSL1("*|Plain text output\n*.xml|XML output");
00591     QString fileName;
00592 
00593     KFileDialog kfile( QString::null , filter, fExportButton , "memoSave" , true );
00594     kfile.setOperationMode( KFileDialog::Saving );
00595 
00596     if ( kfile.exec() == QDialog::Accepted ) {
00597         fileName = kfile.selectedFile();
00598     }
00599 
00600     if (fileName.isEmpty())
00601         return;
00602 
00603     QPtrList<PilotListItem> menu_items;
00604 
00605     for (int x = 0; x < index; x++){
00606         if (fListBox->item(x)->isSelected()){
00607             menu_items.append((PilotListItem *) fListBox->item(x));
00608         }
00609     }
00610 
00611     if (kfile.currentFilter() == CSL1("*.xml") )
00612     {
00613         MemoWidget::saveAsXML( fileName , menu_items );
00614     }
00615     else
00616     {
00617         MemoWidget::saveAsText( fileName , menu_items );
00618     }
00619 
00620 
00621     return;
00622 }
00623 
00624 bool MemoWidget::saveAsText(const QString &fileName,const QPtrList<PilotListItem> &memo_list)
00625 {
00626     QFile f( fileName );
00627     QTextStream stream(&f);
00628 
00629     if ( QFile::exists( fileName ) )
00630     {
00631         if( !f.open(IO_ReadWrite | IO_Append) )
00632         {
00633             return false;
00634         }
00635     }
00636     else
00637     {
00638         if( !f.open(IO_WriteOnly) )
00639         {
00640             return false;
00641         }
00642     }
00643 
00644     QPtrListIterator<PilotListItem> it(memo_list);
00645     for ( ; it.current(); ++it )
00646     {
00647         PilotListItem *p = it.current();
00648         PilotMemo *theMemo = (PilotMemo *) p->rec();
00649         stream << theMemo->text() << endl;
00650     }
00651 
00652 
00653     return true;
00654 }
00655 
00656 bool MemoWidget::saveAsXML(const QString &fileName,const QPtrList<PilotListItem> &memo_list)
00657 {
00658     QDomDocument doc( CSL1("kpilotmemos") );
00659     QFile f( fileName );
00660     QTextStream stream( &f );
00661     QDomElement memos;
00662     int append = 0;
00663 
00664 
00665     if ( f.exists() )
00666     {
00667         if ( !f.open(IO_ReadOnly ) ) return false;
00668 
00669         if ( doc.setContent( &f ) )
00670         {
00671         //
00672         //
00673         //Only if QDom can read the .xml file and set the doc object to be populated with it's contents
00674             memos = doc.documentElement();
00675             if ( memos.tagName()!= CSL1("memos") )
00676             {
00677                 return false;
00678             }
00679                 //
00680                 //
00681                 //This is an XML Document but it isn't a valid KPilot-Memo xml document
00682             else
00683             {
00684                 append = 1;
00685             }
00686                 //
00687                 //
00688                 //This is a valid KPilot memo, and we will append the current memo to the xml
00689         }
00690         else
00691         {
00692         //
00693         //
00694         //We *couldn't* understand the xml.  Return false!
00695             return false;
00696         }
00697     }
00698     else
00699     {
00700         if ( !f.open(IO_ReadWrite ) ) return false;
00701         //
00702         //
00703         //If there's no such file, we are not appending, just opening the file to read/write.
00704     }
00705 
00706     f.close();
00707     // These are temporary, and should be retrieved from the pilot stuff
00708     QString mpilotid;
00709     mpilotid = "1";
00710     //  End of temp variables
00711 
00712     if (append == 1)
00713     {
00714         memos = doc.documentElement();
00715     }
00716     else
00717     {
00718         memos = doc.createElement( CSL1("memos") );
00719         doc.appendChild ( memos );
00720     }
00721 
00722     QPtrListIterator<PilotListItem> it(memo_list);
00723     for ( ; it.current(); ++it )
00724     {
00725         PilotListItem *p = it.current();
00726         PilotMemo *theMemo = (PilotMemo *) p->rec();
00727 
00728 
00729         QDomElement memo = doc.createElement( CSL1("memo") );
00730         memo.setAttribute ( CSL1("pilotid") , mpilotid );
00731         memos.appendChild ( memo );
00732 
00733         //QDomElement category = doc.createElement( "category" );
00734         //head.appendChild ( category );
00735         //
00736         //QDomText categorytext = doc.createTextNode( memo->category() );
00737         //category.appendChild ( categorytext );
00738         //FIXME
00739 
00740         QDomElement title = doc.createElement(CSL1("title" ));
00741         memo.appendChild ( title );
00742 
00743         QDomText titletext = doc.createTextNode( theMemo->shortTitle() );
00744         title.appendChild ( titletext );
00745 
00746         QDomText body = doc.createTextNode( theMemo->text() );
00747         memo.appendChild ( body );
00748     }
00749     if ( !f.open(IO_WriteOnly ) ) return false;
00750     stream << doc.toString();
00751     return true;
00752 }
00753 
KDE Logo
This file is part of the documentation for kpilot Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat May 1 11:36:48 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003