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