kpilot/kpilot

addressWidget.cc

00001 /* KPilot
00002 **
00003 ** Copyright (C) 1998-2001 by Dan Pilone
00004 ** Copyright (C) 2003 Reinhold Kainhofer <reinhold@kainhofer.com>
00005 ** Copyright (C) 2004 by Adriaan de Groot
00006 **
00007 ** This file defines the addressWidget, that part of KPilot that
00008 ** displays address records from the Pilot.
00009 */
00010 
00011 /*
00012 ** This program is free software; you can redistribute it and/or modify
00013 ** it under the terms of the GNU General Public License as published by
00014 ** the Free Software Foundation; either version 2 of the License, or
00015 ** (at your option) any later version.
00016 **
00017 ** This program is distributed in the hope that it will be useful,
00018 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00020 ** GNU General Public License for more details.
00021 **
00022 ** You should have received a copy of the GNU General Public License
00023 ** along with this program in a file called COPYING; if not, write to
00024 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00025 ** MA 02110-1301, USA.
00026 */
00027 
00028 /*
00029 ** Bug reports and questions can be sent to kde-pim@kde.org
00030 */
00031 static const char *addresswidget_id =
00032     "$Id: addressWidget.cc 450284 2005-08-17 20:49:09Z adridg $";
00033 
00034 
00035 
00036 #ifndef _KPILOT_OPTIONS_H
00037 #include "options.h"
00038 #endif
00039 
00040 #include <iostream>
00041 #include <cstring>
00042 #include <cstdlib>
00043 
00044 #include <qptrlist.h>
00045 #include <qlistbox.h>
00046 #include <qfile.h>
00047 #include <qpushbutton.h>
00048 #include <qtextstream.h>
00049 #include <qlayout.h>
00050 #include <qlabel.h>
00051 #include <qmultilineedit.h>
00052 #include <qcombobox.h>
00053 #include <qwhatsthis.h>
00054 #include <qtextview.h>
00055 #include <qtextcodec.h>
00056 #include <qregexp.h>
00057 
00058 #include <kapplication.h>
00059 #include <kmessagebox.h>
00060 #include <kdebug.h>
00061 #include <kfiledialog.h>
00062 
00063 #include "kpilotConfig.h"
00064 #include "listItems.h"
00065 #include "addressEditor.h"
00066 #include "pilotLocalDatabase.h"
00067 
00068 #include "addressWidget.moc"
00069 
00070 
00071 AddressWidget::AddressWidget(QWidget * parent,
00072     const QString & path) :
00073     PilotComponent(parent, "component_address", path),
00074     fAddrInfo(0L),
00075     fAddressAppInfo(0L),
00076     fPendingAddresses(0)
00077 {
00078     FUNCTIONSETUP;
00079 
00080     setupWidget();
00081     fAddressList.setAutoDelete(true);
00082 
00083     /* NOTREACHED */
00084     (void) addresswidget_id;
00085 }
00086 
00087 AddressWidget::~AddressWidget()
00088 {
00089     FUNCTIONSETUP;
00090 }
00091 
00092 int AddressWidget::getAllAddresses(PilotDatabase * addressDB)
00093 {
00094     FUNCTIONSETUP;
00095 
00096     int currentRecord = 0;
00097     PilotRecord *pilotRec;
00098     PilotAddress *address;
00099 
00100 
00101 #ifdef DEBUG
00102     DEBUGKPILOT << fname << ": Reading AddressDB..." << endl;
00103 #endif
00104 
00105     while ((pilotRec = addressDB->readRecordByIndex(currentRecord)) != 0L)
00106     {
00107         if (!(pilotRec->isDeleted()) &&
00108             (!(pilotRec->isSecret()) || KPilotSettings::showSecrets()))
00109         {
00110             address = new PilotAddress(fAddressAppInfo, pilotRec);
00111             if (address == 0L)
00112             {
00113                 kdWarning() << k_funcinfo
00114                     << ": Couldn't allocate record "
00115                     << currentRecord++
00116                     << endl;
00117                 break;
00118             }
00119             fAddressList.append(address);
00120         }
00121         delete pilotRec;
00122 
00123         currentRecord++;
00124     }
00125 
00126 #ifdef DEBUG
00127     DEBUGKPILOT << fname
00128         << ": Total " << currentRecord << " records" << endl;
00129 #endif
00130 
00131     return currentRecord;
00132 }
00133 
00134 void AddressWidget::showComponent()
00135 {
00136     FUNCTIONSETUP;
00137     if ( fPendingAddresses>0 ) return;
00138 
00139 #ifdef DEBUG
00140     DEBUGKPILOT << fname
00141         << ": Reading from directory " << dbPath() << endl;
00142 #endif
00143 
00144     PilotDatabase *addressDB =
00145         new PilotLocalDatabase(dbPath(), CSL1("AddressDB"));
00146 
00147     fAddressList.clear();
00148 
00149     if (addressDB->isDBOpen())
00150     {
00151         KPILOT_DELETE(fAddressAppInfo);
00152         fAddressAppInfo = new PilotAddressInfo(addressDB);
00153         populateCategories(fCatList, fAddressAppInfo->categoryInfo());
00154         getAllAddresses(addressDB);
00155 
00156     }
00157     else
00158     {
00159         populateCategories(fCatList, 0L);
00160         kdWarning() << k_funcinfo
00161             << ": Could not open local AddressDB" << endl;
00162     }
00163 
00164     KPILOT_DELETE( addressDB );
00165 
00166     updateWidget();
00167 }
00168 
00169 void AddressWidget::hideComponent()
00170 {
00171     FUNCTIONSETUP;
00172     if (fPendingAddresses==0 )
00173     {
00174         fAddressList.clear();
00175         fListBox->clear();
00176 
00177         updateWidget();
00178     }
00179 }
00180 
00181 /* virtual */ bool AddressWidget::preHotSync(QString &s)
00182 {
00183     FUNCTIONSETUP;
00184 
00185     if ( fPendingAddresses )
00186     {
00187 #ifdef DEBUG
00188         DEBUGKPILOT << fname
00189             << ": fPendingAddress="
00190             << fPendingAddresses
00191             << endl;
00192 #endif
00193 
00194 #if KDE_VERSION<220
00195         s = i18n("There are still %1 address editing windows open.")
00196             .arg(QString::number(fPendingAddresses));
00197 #else
00198         s = i18n("There is still an address editing window open.",
00199             "There are still %n address editing windows open.",
00200             fPendingAddresses);
00201 #endif
00202         return false;
00203     }
00204 
00205     return true;
00206 }
00207 
00208 void AddressWidget::postHotSync()
00209 {
00210     FUNCTIONSETUP;
00211 
00212     if ( shown )
00213     {
00214         fAddressList.clear();
00215         showComponent();
00216     }
00217 }
00218 
00219 
00220 void AddressWidget::setupWidget()
00221 {
00222     FUNCTIONSETUP;
00223 
00224     QLabel *label;
00225     QGridLayout *grid = new QGridLayout(this, 6, 4, SPACING);
00226 
00227     fCatList = new QComboBox(this);
00228     grid->addWidget(fCatList, 0, 1);
00229     connect(fCatList, SIGNAL(activated(int)),
00230         this, SLOT(slotSetCategory(int)));
00231     QWhatsThis::add(fCatList,
00232         i18n("<qt>Select the category of addresses to display here.</qt>"));
00233 
00234     label = new QLabel(i18n("Category:"), this);
00235     label->setBuddy(fCatList);
00236     grid->addWidget(label, 0, 0);
00237 
00238     fListBox = new QListBox(this);
00239     grid->addMultiCellWidget(fListBox, 1, 1, 0, 1);
00240     connect(fListBox, SIGNAL(highlighted(int)),
00241         this, SLOT(slotShowAddress(int)));
00242     connect(fListBox, SIGNAL(selected(int)),
00243         this, SLOT(slotEditRecord()));
00244     QWhatsThis::add(fListBox,
00245         i18n("<qt>This list displays all the addresses "
00246             "in the selected category. Click on "
00247             "one to display it to the right.</qt>"));
00248 
00249     label = new QLabel(i18n("Address info:"), this);
00250     grid->addWidget(label, 0, 2);
00251 
00252     // address info text view
00253     fAddrInfo = new QTextView(this);
00254     grid->addMultiCellWidget(fAddrInfo, 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     wt = KPilotSettings::internalEditors() ?
00263         i18n("<qt>You can edit an address when it is selected.</qt>") :
00264         i18n("<qt><i>Editing is disabled by the 'internal editors' setting.</i></qt>");
00265     QWhatsThis::add(fEditButton,wt);
00266 
00267     button = new QPushButton(i18n("New Record..."), this);
00268     grid->addWidget(button, 2, 1);
00269     connect(button, SIGNAL(clicked()), this, SLOT(slotCreateNewRecord()));
00270     wt = KPilotSettings::internalEditors() ?
00271         i18n("<qt>Add a new address to the address book.</qt>") :
00272         i18n("<qt><i>Adding is disabled by the 'internal editors' setting.</i></qt>") ;
00273     QWhatsThis::add(button, wt);
00274     button->setEnabled(KPilotSettings::internalEditors());
00275 
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 address from the address book.</qt>") :
00283         i18n("<qt><i>Deleting is disabled by the 'internal editors' setting.</i></qt>") ;
00284 
00285     button = new QPushButton(TODO_I18N("Export..."), this);
00286     grid->addWidget(button, 3,1);
00287     connect(button, SIGNAL(clicked()), this, SLOT(slotExport()));
00288     QWhatsThis::add(button,
00289         TODO_I18N("<qt>Export all addresses in the selected category to CSV format.</qt>") );
00290 
00291     QWhatsThis::add(fDeleteButton,wt);
00292 }
00293 
00294 void AddressWidget::updateWidget()
00295 {
00296     FUNCTIONSETUP;
00297 
00298     if( !fAddressAppInfo )
00299             return;
00300     int addressDisplayMode = KPilotSettings::addressDisplayMode();
00301 
00302     int listIndex = 0;
00303 
00304 #ifdef DEBUG
00305     DEBUGKPILOT << fname
00306         << ": Display Mode=" << addressDisplayMode << endl;
00307 #endif
00308 
00309     int currentCatID = findSelectedCategory(fCatList,
00310         fAddressAppInfo->categoryInfo());
00311 
00312     fListBox->clear();
00313     fAddressList.first();
00314 
00315 #ifdef DEBUG
00316     DEBUGKPILOT << fname << ": Adding records..." << endl;
00317 #endif
00318 
00319     while (fAddressList.current())
00320     {
00321         if ((currentCatID == -1) ||
00322             (fAddressList.current()->category() == currentCatID))
00323         {
00324             QString title = createTitle(fAddressList.current(),
00325                 addressDisplayMode);
00326 
00327             if (!title.isEmpty())
00328             {
00329                 title.remove(QRegExp(CSL1("\n.*")));
00330                 PilotListItem *p = new PilotListItem(title,
00331                     listIndex,
00332                     fAddressList.current());
00333 
00334                 fListBox->insertItem(p);
00335             }
00336         }
00337         listIndex++;
00338         fAddressList.next();
00339     }
00340 
00341     fListBox->sort();
00342 #ifdef DEBUG
00343     DEBUGKPILOT << fname << ": " << listIndex << " records" << endl;
00344 #endif
00345 
00346     slotUpdateButtons();
00347 }
00348 
00349 
00350 
00351 QString AddressWidget::createTitle(PilotAddress * address, int displayMode)
00352 {
00353     // FUNCTIONSETUP;
00354 
00355     QString title;
00356 
00357     switch (displayMode)
00358     {
00359     case 1:
00360         if (!address->getField(entryCompany).isEmpty())
00361         {
00362             title.append(address->getField(entryCompany));
00363         }
00364         if (!address->getField(entryLastname).isEmpty())
00365         {
00366             if (!title.isEmpty())
00367             {
00368                 title.append( CSL1(", "));
00369             }
00370 
00371             title.append(address->getField(entryLastname));
00372         }
00373         break;
00374     case 0:
00375     default:
00376         if (!address->getField(entryLastname).isEmpty())
00377         {
00378             title.append(address->getField(entryLastname));
00379         }
00380 
00381         if (!address->getField(entryFirstname).isEmpty())
00382         {
00383             if (!title.isEmpty())
00384             {
00385                 title.append( CSL1(", "));
00386             }
00387             title.append(address->getField(entryFirstname));
00388         }
00389         break;
00390     }
00391 
00392     if (title.isEmpty())    // One last try
00393     {
00394         if (!fAddressList.current()->getField(entryCompany).isEmpty())
00395         {
00396             title.append(fAddressList.current()->
00397                 getField(entryCompany));
00398         }
00399         if (title.isEmpty())
00400         {
00401             title = i18n("[unknown]");
00402         }
00403     }
00404 
00405     return title;
00406 }
00407 
00408 
00409 /* slot */ void AddressWidget::slotUpdateButtons()
00410 {
00411     FUNCTIONSETUP;
00412 
00413     bool enabled = (fListBox->currentItem() != -1);
00414 
00415     enabled &= KPilotSettings::internalEditors();
00416     fEditButton->setEnabled(enabled);
00417     fDeleteButton->setEnabled(enabled);
00418 }
00419 
00420 void AddressWidget::slotSetCategory(int)
00421 {
00422     FUNCTIONSETUP;
00423 
00424     updateWidget();
00425 }
00426 
00427 void AddressWidget::slotEditRecord()
00428 {
00429     FUNCTIONSETUP;
00430     if ( !shown ) return;
00431 
00432     int item = fListBox->currentItem();
00433 
00434     if (item == -1)
00435         return;
00436 
00437     PilotListItem *p = (PilotListItem *) fListBox->item(item);
00438     PilotAddress *selectedRecord = (PilotAddress *) p->rec();
00439 
00440     if (selectedRecord->id() == 0)
00441     {
00442         KMessageBox::error(0L,
00443             i18n("Cannot edit new records until "
00444                 "HotSynced with Pilot."),
00445             i18n("HotSync Required"));
00446         return;
00447     }
00448 
00449     AddressEditor *editor = new AddressEditor(selectedRecord,
00450         fAddressAppInfo->info(), this);
00451 
00452     connect(editor, SIGNAL(recordChangeComplete(PilotAddress *)),
00453         this, SLOT(slotUpdateRecord(PilotAddress *)));
00454     connect(editor, SIGNAL(cancelClicked()),
00455         this, SLOT(slotEditCancelled()));
00456     editor->show();
00457 
00458     fPendingAddresses++;
00459 }
00460 
00461 void AddressWidget::slotCreateNewRecord()
00462 {
00463     FUNCTIONSETUP;
00464     if ( !shown ) return;
00465 
00466     // Response to bug 18072: Don't even try to
00467     // add records to an empty or unopened database,
00468     // since we don't have the DBInfo stuff to deal with it.
00469     //
00470     //
00471     PilotDatabase *myDB = new PilotLocalDatabase(dbPath(), CSL1("AddressDB"));
00472 
00473     if (!myDB || !myDB->isDBOpen())
00474     {
00475 #ifdef DEBUG
00476         DEBUGKPILOT << fname
00477             << ": Tried to open "
00478             << dbPath()
00479             << "/AddressDB"
00480             << " and got pointer @"
00481             << (long) myDB
00482             << " with status "
00483             << ( myDB ? myDB->isDBOpen() : false )
00484             << endl;
00485 #endif
00486 
00487         KMessageBox::sorry(this,
00488             i18n("You cannot add addresses to the address book "
00489                 "until you have done a HotSync at least once "
00490                 "to retrieve the database layout from your Pilot."),
00491             i18n("Cannot Add New Address"));
00492 
00493         if (myDB)
00494             KPILOT_DELETE( myDB );
00495 
00496         return;
00497     }
00498 
00499     AddressEditor *editor = new AddressEditor(0L,
00500         fAddressAppInfo->info(), this);
00501 
00502     connect(editor, SIGNAL(recordChangeComplete(PilotAddress *)),
00503         this, SLOT(slotAddRecord(PilotAddress *)));
00504     connect(editor, SIGNAL(cancelClicked()),
00505         this, SLOT(slotEditCancelled()));
00506     editor->show();
00507 
00508     fPendingAddresses++;
00509 }
00510 
00511 void AddressWidget::slotAddRecord(PilotAddress * address)
00512 {
00513     FUNCTIONSETUP;
00514     if ( !shown && fPendingAddresses==0 ) return;
00515 
00516     int currentCatID = findSelectedCategory(fCatList,
00517         fAddressAppInfo->categoryInfo(), true);
00518 
00519 
00520     address->PilotAppCategory::setCategory(currentCatID);
00521     fAddressList.append(address);
00522     writeAddress(address);
00523     // TODO: Just add the new record to the lists
00524     updateWidget();
00525 
00526     // k holds the item number of the address just added.
00527     //
00528     //
00529     int k = fListBox->count() - 1;
00530 
00531     fListBox->setCurrentItem(k);    // Show the newest one
00532     fListBox->setBottomItem(k);
00533 
00534     fPendingAddresses--;
00535     if ( !shown && fPendingAddresses==0 ) hideComponent();
00536 }
00537 
00538 void AddressWidget::slotUpdateRecord(PilotAddress * address)
00539 {
00540     FUNCTIONSETUP;
00541     if ( !shown && fPendingAddresses==0 ) return;
00542 
00543     writeAddress(address);
00544     int currentRecord = fListBox->currentItem();
00545 
00546     // TODO: Just change the record
00547     updateWidget();
00548     fListBox->setCurrentItem(currentRecord);
00549 
00550     emit(recordChanged(address));
00551 
00552     fPendingAddresses--;
00553     if ( !shown && fPendingAddresses==0 ) hideComponent();
00554 }
00555 
00556 void AddressWidget::slotEditCancelled()
00557 {
00558     FUNCTIONSETUP;
00559 
00560     fPendingAddresses--;
00561     if ( !shown && fPendingAddresses==0 ) hideComponent();
00562 }
00563 
00564 void AddressWidget::slotDeleteRecord()
00565 {
00566     FUNCTIONSETUP;
00567     if ( !shown ) return;
00568 
00569     int item = fListBox->currentItem();
00570 
00571     if (item == -1)
00572         return;
00573 
00574     PilotListItem *p = (PilotListItem *) fListBox->item(item);
00575     PilotAddress *selectedRecord = (PilotAddress *) p->rec();
00576 
00577     if (selectedRecord->id() == 0)
00578     {
00579         KMessageBox::error(this,
00580             i18n("New records cannot be deleted until "
00581                 "HotSynced with pilot."),
00582             i18n("HotSync Required"));
00583         return;
00584     }
00585 
00586     if (KMessageBox::questionYesNo(this,
00587             i18n("Delete currently selected record?"),
00588             i18n("Delete Record?"), KStdGuiItem::del(), KStdGuiItem::cancel()) == KMessageBox::No)
00589         return;
00590 
00591     selectedRecord->setDeleted( true );
00592     writeAddress(selectedRecord);
00593     emit(recordChanged(selectedRecord));
00594     showComponent();
00595 }
00596 
00597 
00598 
00599 void AddressWidget::slotShowAddress(int which)
00600 {
00601     FUNCTIONSETUP;
00602     if (!shown) return;
00603 
00604     PilotListItem *p = (PilotListItem *) fListBox->item(which);
00605     PilotAddress *addr = (PilotAddress *) p->rec();
00606 
00607 #ifdef DEBUG
00608     DEBUGKPILOT << fname
00609         << ": Showing "
00610         << addr->getField(entryLastname)
00611         << " "
00612         << addr->getField(entryFirstname)
00613         << endl;
00614 #endif
00615 
00616     QString text(CSL1("<qt>"));
00617     text += addr->getTextRepresentation(true);
00618     text += CSL1("</qt>\n");
00619     fAddrInfo->setText(text);
00620 
00621     slotUpdateButtons();
00622 }
00623 
00624 
00625 
00626 void AddressWidget::writeAddress(PilotAddress * which,
00627     PilotDatabase * addressDB)
00628 {
00629     FUNCTIONSETUP;
00630 
00631     // Open a database (myDB) only if needed,
00632     // i.e. only if the passed-in addressDB
00633     // isn't valid.
00634     //
00635     //
00636     PilotDatabase *myDB = addressDB;
00637     bool usemyDB = false;
00638 
00639     if (myDB == 0L || !myDB->isDBOpen())
00640     {
00641         myDB = new PilotLocalDatabase(dbPath(), CSL1("AddressDB"));
00642         usemyDB = true;
00643     }
00644 
00645     // Still no valid address database...
00646     //
00647     //
00648     if (!myDB->isDBOpen())
00649     {
00650 #ifdef DEBUG
00651         DEBUGKPILOT << fname << ": Address database is not open" <<
00652             endl;
00653 #endif
00654         return;
00655     }
00656 
00657 
00658     // Do the actual work.
00659     PilotRecord *pilotRec = which->pack();
00660 
00661     myDB->writeRecord(pilotRec);
00662     markDBDirty(CSL1("AddressDB"));
00663     delete pilotRec;
00664 
00665     // Clean up in the case that we allocated our own DB.
00666     //
00667     //
00668     if (usemyDB)
00669     {
00670         KPILOT_DELETE( myDB );
00671     }
00672 }
00673 
00674 #define plu_quiet 1
00675 #include "pilot-addresses.c"
00676 
00677 void AddressWidget::slotExport()
00678 {
00679     FUNCTIONSETUP;
00680     if( !fAddressAppInfo ) return;
00681     int currentCatID = findSelectedCategory(fCatList,
00682         fAddressAppInfo->categoryInfo());
00683 
00684     QString prompt = (currentCatID==-1) ?
00685         i18n("Export All Addresses") :
00686         i18n("Export Address Category %1").arg(fAddressAppInfo->category(currentCatID)) ;
00687 
00688 
00689     QString saveFile = KFileDialog::getSaveFileName(
00690         QString::null,
00691         CSL1("*.csv|Comma Separated Values"),
00692         this,
00693         prompt
00694         );
00695     if (saveFile.isEmpty())
00696     {
00697 #ifdef DEBUG
00698         DEBUGKPILOT << fname << ": No save file selected." << endl;
00699 #endif
00700         return;
00701     }
00702     if (QFile::exists(saveFile) &&
00703         KMessageBox::warningContinueCancel(this,
00704             i18n("The file <i>%1</i> exists. Overwrite?").arg(saveFile),
00705             i18n("Overwrite File?"),
00706             i18n("Overwrite"))!=KMessageBox::Continue)
00707     {
00708 #ifdef DEBUG
00709         DEBUGKPILOT << fname << ": Overwrite file canceled." << endl;
00710 #endif
00711         return;
00712     }
00713 
00714     FILE *f = fopen(QFile::encodeName(saveFile),"w");
00715     if (!f)
00716     {
00717         KMessageBox::sorry(this,
00718             i18n("The file <i>%1</i> could not be opened for writing.").arg(saveFile));
00719         return;
00720     }
00721     fAddressList.first();
00722 
00723 #ifdef DEBUG
00724     DEBUGKPILOT << fname << ": Adding records..." << endl;
00725 #endif
00726 
00727     while (fAddressList.current())
00728     {
00729         const PilotAddress *a = fAddressList.current();
00730         if ((currentCatID == -1) ||
00731             (a->category() == currentCatID))
00732         {
00733             write_record_CSV(f, fAddressAppInfo->info(), a->address(),
00734                 a->attributes(), a->category(), 0);
00735         }
00736         fAddressList.next();
00737     }
00738 
00739     fclose(f);
00740 }
00741 
KDE Home | KDE Accessibility Home | Description of Access Keys