kaddressbook

customfieldswidget.cpp

00001 /*
00002     This file is part of KAddressbook.
00003     Copyright (c) 2004 Tobias Koenig <tokoe@kde.org>
00004 
00005     This program is free software; you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published by
00007     the Free Software Foundation; either version 2 of the License, or
00008     (at your option) any later version.
00009 
00010     This program is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with this program; if not, write to the Free Software
00017     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018 
00019     As a special exception, permission is given to link this program
00020     with any edition of Qt, and distribute the resulting executable,
00021     without including the source code for Qt in the source distribution.
00022 */
00023 
00024 #include <qcheckbox.h>
00025 #include <qdatetimeedit.h>
00026 #include <qframe.h>
00027 #include <qlabel.h>
00028 #include <qlayout.h>
00029 #include <qpushbutton.h>
00030 #include <qvalidator.h>
00031 #include <qspinbox.h>
00032 
00033 #include <kaccelmanager.h>
00034 #include <kcombobox.h>
00035 #include <kinputdialog.h>
00036 #include <klineedit.h>
00037 #include <kmessagebox.h>
00038 
00039 #include "addresseeconfig.h"
00040 #include "kabprefs.h"
00041 
00042 #include "customfieldswidget.h"
00043 
00044 
00045 AddFieldDialog::AddFieldDialog( QWidget *parent, const char *name )
00046   : KDialogBase( Plain, i18n( "Add Field" ), Ok | Cancel,
00047                  Ok, parent, name, true, true )
00048 {
00049   QWidget *page = plainPage();
00050 
00051   QGridLayout *layout = new QGridLayout( page, 3, 2, marginHint(), spacingHint() );
00052 
00053   QLabel *label = new QLabel( i18n( "Title:" ), page );
00054   layout->addWidget( label, 0, 0 );
00055 
00056   mTitle = new KLineEdit( page );
00057   mTitle->setValidator( new QRegExpValidator( QRegExp( "([a-zA-Z]|\\d|-)+" ), mTitle ) );
00058   label->setBuddy( mTitle );
00059   layout->addWidget( mTitle, 0, 1 );
00060 
00061   label = new QLabel( i18n( "Type:" ), page );
00062   layout->addWidget( label, 1, 0 );
00063 
00064   mType = new KComboBox( page );
00065   label->setBuddy( mType );
00066   layout->addWidget( mType, 1, 1 );
00067 
00068   mGlobal = new QCheckBox( i18n( "Is available for all contacts" ), page );
00069   mGlobal->setChecked( true );
00070   layout->addMultiCellWidget( mGlobal, 2, 2, 0, 1 );
00071 
00072   connect( mTitle, SIGNAL( textChanged( const QString& ) ),
00073            this, SLOT( nameChanged( const QString& ) ) );
00074 
00075   KAcceleratorManager::manage( this );
00076 
00077   mTypeList.append( "text" );
00078   mTypeName.append( i18n( "Text" ) );
00079   mTypeList.append( "integer" );
00080   mTypeName.append( i18n( "Numeric Value" ) );
00081   mTypeList.append( "boolean" );
00082   mTypeName.append( i18n( "Boolean" ) );
00083   mTypeList.append( "date" );
00084   mTypeName.append( i18n( "Date" ) );
00085   mTypeList.append( "time" );
00086   mTypeName.append( i18n( "Time" ) );
00087   mTypeList.append( "datetime" );
00088   mTypeName.append( i18n( "Date & Time" ) );
00089 
00090   for ( uint i = 0; i < mTypeName.count(); ++i )
00091     mType->insertItem( mTypeName[ i ] );
00092 
00093   nameChanged( "" );
00094 
00095   mTitle->setFocus();
00096 }
00097 
00098 QString AddFieldDialog::title() const
00099 {
00100   return mTitle->text();
00101 }
00102 
00103 QString AddFieldDialog::identifier() const
00104 {
00105   QString id = mTitle->text().lower();
00106   return id.replace( ",", "_" ).replace( " ", "_" );
00107 }
00108 
00109 QString AddFieldDialog::type() const
00110 {
00111   return mTypeList[ mType->currentItem() ];
00112 }
00113 
00114 bool AddFieldDialog::isGlobal() const
00115 {
00116   return mGlobal->isChecked();
00117 }
00118 
00119 void AddFieldDialog::nameChanged( const QString &name )
00120 {
00121   enableButton( Ok, !name.isEmpty() );
00122 }
00123 
00124 FieldWidget::FieldWidget( QWidget *parent, const char *name )
00125   : QWidget( parent, name )
00126 {
00127   QVBoxLayout *layout = new QVBoxLayout( this, KDialog::marginHint(),
00128                                          KDialog::spacingHint() );
00129 
00130   mGlobalLayout = new QVBoxLayout( layout, KDialog::spacingHint() );
00131   mGlobalLayout->setAlignment( Qt::AlignTop );
00132 
00133   mSeparator = new QFrame( this );
00134   mSeparator->setFrameStyle( QFrame::HLine | QFrame::Sunken );
00135   mSeparator->hide();
00136   layout->addWidget( mSeparator );
00137 
00138   mLocalLayout = new QVBoxLayout( layout, KDialog::spacingHint() );
00139   mLocalLayout->setAlignment( Qt::AlignTop );
00140 }
00141 
00142 void FieldWidget::addField( const QString &identifier, const QString &title,
00143                             const QString &type, bool isGlobal )
00144 {
00145   FieldRecord record;
00146 
00147   record.mIdentifier = identifier;
00148   record.mTitle = title;
00149   record.mLabel = new QLabel( title + ":", this );
00150   record.mGlobal = isGlobal;
00151   if ( type == "integer" ) {
00152     QSpinBox *wdg = new QSpinBox( 0, 1000, 1, this );
00153     record.mWidget = wdg;
00154     connect( wdg, SIGNAL( valueChanged( int ) ),
00155              this, SIGNAL( changed() ) );
00156   } else if ( type == "boolean" ) {
00157     QCheckBox *wdg = new QCheckBox( this );
00158     record.mWidget = wdg;
00159     connect( wdg, SIGNAL( toggled( bool ) ),
00160              this, SIGNAL( changed() ) );
00161   } else if ( type == "date" ) {
00162     QDateEdit *wdg = new QDateEdit( this );
00163     record.mWidget = wdg;
00164     connect( wdg, SIGNAL( valueChanged( const QDate& ) ),
00165              this, SIGNAL( changed() ) );
00166   } else if ( type == "time" ) {
00167     QTimeEdit *wdg = new QTimeEdit( this );
00168     record.mWidget = wdg;
00169     connect( wdg, SIGNAL( valueChanged( const QTime& ) ),
00170              this, SIGNAL( changed() ) );
00171   } else if ( type == "datetime" ) {
00172     QDateTimeEdit *wdg = new QDateTimeEdit( this );
00173     record.mWidget = wdg;
00174     connect( wdg, SIGNAL( valueChanged( const QDateTime& ) ),
00175              this, SIGNAL( changed() ) );
00176   } else  if ( type == "text" ) {
00177     QLineEdit *wdg = new QLineEdit( this );
00178     record.mWidget = wdg;
00179     connect( wdg, SIGNAL( textChanged( const QString& ) ),
00180              this, SIGNAL( changed() ) );
00181   }
00182 
00183   record.mLabel->show();
00184   record.mWidget->show();
00185 
00186   if ( isGlobal ) {
00187     record.mLayout = new QHBoxLayout( mGlobalLayout );
00188     record.mLayout->addWidget( record.mLabel );
00189     record.mLayout->addWidget( record.mWidget, Qt::AlignLeft );
00190   } else {
00191     record.mLayout = new QHBoxLayout( mLocalLayout );
00192     record.mLayout->addWidget( record.mLabel );
00193     record.mLayout->addWidget( record.mWidget, Qt::AlignLeft );
00194     mSeparator->show();
00195   }
00196 
00197   mFieldList.append( record );
00198 
00199   recalculateLayout();
00200 }
00201 
00202 void FieldWidget::removeField( const QString &identifier )
00203 {
00204   FieldRecordList::Iterator it;
00205   for ( it = mFieldList.begin(); it != mFieldList.end(); ++it ) {
00206     if ( (*it).mIdentifier == identifier ) {
00207       delete (*it).mLabel;
00208       delete (*it).mWidget;
00209       delete (*it).mLayout;
00210 
00211       mFieldList.remove( it );
00212       recalculateLayout();
00213 
00214       bool hasLocal = false;
00215       for ( it = mFieldList.begin(); it != mFieldList.end(); ++it )
00216         hasLocal = hasLocal || !(*it).mGlobal;
00217 
00218       if ( !hasLocal )
00219         mSeparator->hide();
00220 
00221       return;
00222     }
00223   }
00224 }
00225 
00226 void FieldWidget::clearFields()
00227 {
00228   FieldRecordList::ConstIterator fieldIt;
00229   for ( fieldIt = mFieldList.begin(); fieldIt != mFieldList.end(); ++fieldIt ) {
00230     if ( (*fieldIt).mWidget->isA( "QLineEdit" ) ) {
00231       QLineEdit *wdg = static_cast<QLineEdit*>( (*fieldIt).mWidget );
00232       wdg->setText( QString() );
00233     } else if ( (*fieldIt).mWidget->isA( "QSpinBox" ) ) {
00234       QSpinBox *wdg = static_cast<QSpinBox*>( (*fieldIt).mWidget );
00235       wdg->setValue( 0 );
00236     } else if ( (*fieldIt).mWidget->isA( "QCheckBox" ) ) {
00237       QCheckBox *wdg = static_cast<QCheckBox*>( (*fieldIt).mWidget );
00238       wdg->setChecked( true );
00239     } else if ( (*fieldIt).mWidget->isA( "QDateEdit" ) ) {
00240       QDateEdit *wdg = static_cast<QDateEdit*>( (*fieldIt).mWidget );
00241       wdg->setDate( QDate::currentDate() );
00242     } else if ( (*fieldIt).mWidget->isA( "QTimeEdit" ) ) {
00243       QTimeEdit *wdg = static_cast<QTimeEdit*>( (*fieldIt).mWidget );
00244       wdg->setTime( QTime::currentTime() );
00245     } else if ( (*fieldIt).mWidget->isA( "QDateTimeEdit" ) ) {
00246       QDateTimeEdit *wdg = static_cast<QDateTimeEdit*>( (*fieldIt).mWidget );
00247       wdg->setDateTime( QDateTime::currentDateTime() );
00248     }
00249   }
00250 }
00251 
00252 void FieldWidget::loadContact( KABC::Addressee *addr )
00253 {
00254   const QStringList customs = addr->customs();
00255 
00256   clearFields();
00257 
00258   QStringList::ConstIterator it;
00259   for ( it = customs.begin(); it != customs.end(); ++it ) {
00260     QString app, name, value;
00261     splitField( *it, app, name, value );
00262     if ( app != "KADDRESSBOOK" )
00263       continue;
00264 
00265     FieldRecordList::ConstIterator fieldIt;
00266     for ( fieldIt = mFieldList.begin(); fieldIt != mFieldList.end(); ++fieldIt ) {
00267       if ( (*fieldIt).mIdentifier == name ) {
00268         if ( (*fieldIt).mWidget->isA( "QLineEdit" ) ) {
00269           QLineEdit *wdg = static_cast<QLineEdit*>( (*fieldIt).mWidget );
00270           wdg->setText( value );
00271         } else if ( (*fieldIt).mWidget->isA( "QSpinBox" ) ) {
00272           QSpinBox *wdg = static_cast<QSpinBox*>( (*fieldIt).mWidget );
00273           wdg->setValue( value.toInt() );
00274         } else if ( (*fieldIt).mWidget->isA( "QCheckBox" ) ) {
00275           QCheckBox *wdg = static_cast<QCheckBox*>( (*fieldIt).mWidget );
00276           wdg->setChecked( value == "true" || value == "1" );
00277         } else if ( (*fieldIt).mWidget->isA( "QDateEdit" ) ) {
00278           QDateEdit *wdg = static_cast<QDateEdit*>( (*fieldIt).mWidget );
00279           wdg->setDate( QDate::fromString( value, Qt::ISODate ) );
00280         } else if ( (*fieldIt).mWidget->isA( "QTimeEdit" ) ) {
00281           QTimeEdit *wdg = static_cast<QTimeEdit*>( (*fieldIt).mWidget );
00282           wdg->setTime( QTime::fromString( value, Qt::ISODate ) );
00283         } else if ( (*fieldIt).mWidget->isA( "QDateTimeEdit" ) ) {
00284           QDateTimeEdit *wdg = static_cast<QDateTimeEdit*>( (*fieldIt).mWidget );
00285           wdg->setDateTime( QDateTime::fromString( value, Qt::ISODate ) );
00286         }
00287       }
00288     }
00289   }
00290 }
00291 
00292 void FieldWidget::storeContact( KABC::Addressee *addr )
00293 {
00294   FieldRecordList::ConstIterator it;
00295   for ( it = mFieldList.begin(); it != mFieldList.end(); ++it ) {
00296     QString value;
00297     if ( (*it).mWidget->isA( "QLineEdit" ) ) {
00298       QLineEdit *wdg = static_cast<QLineEdit*>( (*it).mWidget );
00299       value = wdg->text();
00300     } else if ( (*it).mWidget->isA( "QSpinBox" ) ) {
00301       QSpinBox *wdg = static_cast<QSpinBox*>( (*it).mWidget );
00302       value = QString::number( wdg->value() );
00303     } else if ( (*it).mWidget->isA( "QCheckBox" ) ) {
00304       QCheckBox *wdg = static_cast<QCheckBox*>( (*it).mWidget );
00305       value = ( wdg->isChecked() ? "true" : "false" );
00306     } else if ( (*it).mWidget->isA( "QDateEdit" ) ) {
00307       QDateEdit *wdg = static_cast<QDateEdit*>( (*it).mWidget );
00308       value = wdg->date().toString( Qt::ISODate );
00309     } else if ( (*it).mWidget->isA( "QTimeEdit" ) ) {
00310       QTimeEdit *wdg = static_cast<QTimeEdit*>( (*it).mWidget );
00311       value = wdg->time().toString( Qt::ISODate );
00312     } else if ( (*it).mWidget->isA( "QDateTimeEdit" ) ) {
00313       QDateTimeEdit *wdg = static_cast<QDateTimeEdit*>( (*it).mWidget );
00314       value = wdg->dateTime().toString( Qt::ISODate );
00315     }
00316 
00317     if ( value.isEmpty() )
00318       addr->removeCustom( "KADDRESSBOOK", (*it).mIdentifier );
00319     else
00320       addr->insertCustom( "KADDRESSBOOK", (*it).mIdentifier, value );
00321   }
00322 }
00323 
00324 void FieldWidget::removeLocalFields()
00325 {
00326   FieldRecordList::Iterator it;
00327   for ( it = mFieldList.begin(); it != mFieldList.end(); ++it ) {
00328     if ( !(*it).mGlobal ) {
00329       delete (*it).mLabel;
00330       delete (*it).mWidget;
00331       delete (*it).mLayout;
00332 
00333       it = mFieldList.remove( it );
00334       it--;
00335       recalculateLayout();
00336     }
00337   }
00338 }
00339 
00340 void FieldWidget::recalculateLayout()
00341 {
00342   int maxWidth = 0;
00343 
00344   FieldRecordList::ConstIterator it;
00345   for ( it = mFieldList.begin(); it != mFieldList.end(); ++it )
00346     maxWidth = QMAX( maxWidth, (*it).mLabel->minimumSizeHint().width() );
00347 
00348   for ( it = mFieldList.begin(); it != mFieldList.end(); ++it )
00349     (*it).mLabel->setMinimumWidth( maxWidth );
00350 }
00351 
00352 CustomFieldsWidget::CustomFieldsWidget( KABC::AddressBook *ab,
00353                                         QWidget *parent, const char *name )
00354   : KAB::ContactEditorWidget( ab, parent, name )
00355 {
00356   initGUI();
00357 
00358   connect( mAddButton, SIGNAL( clicked() ), this, SLOT( addField() ) );
00359   connect( mRemoveButton, SIGNAL( clicked() ), this, SLOT( removeField() ) );
00360 
00361   connect( mFieldWidget, SIGNAL( changed() ), this, SLOT( setModified() ) );
00362 }
00363 
00364 void CustomFieldsWidget::loadContact( KABC::Addressee *addr )
00365 {
00366   mAddressee = *addr;
00367 
00368   mFieldWidget->removeLocalFields();
00369 
00370   AddresseeConfig addrConfig( mAddressee );
00371   QStringList fields = addrConfig.customFields();
00372 
00373   if ( !fields.isEmpty() ) {
00374     for ( uint i = 0; i < fields.count(); i += 3 ) {
00375       mFieldWidget->addField( fields[ i ], fields[ i + 1 ],
00376                               fields[ i + 2 ] , false );
00377       mRemoveButton->setEnabled( true );
00378     }
00379   }
00380 
00381   mFieldWidget->loadContact( addr );
00382 }
00383 
00384 void CustomFieldsWidget::storeContact( KABC::Addressee *addr )
00385 {
00386   mFieldWidget->storeContact( addr );
00387 }
00388 
00389 void CustomFieldsWidget::setReadOnly( bool readOnly )
00390 {
00391   mAddButton->setEnabled( !readOnly );
00392   mRemoveButton->setEnabled( !readOnly && !mFieldWidget->fields().isEmpty() );
00393 }
00394 
00395 void CustomFieldsWidget::addField()
00396 {
00397   AddFieldDialog dlg( this );
00398 
00399   if ( dlg.exec() ) {
00400     FieldRecordList list = mFieldWidget->fields();
00401 
00402     FieldRecordList::ConstIterator it;
00403     for ( it = list.begin(); it != list.end(); ++it )
00404       if ( (*it).mIdentifier == dlg.identifier() ) {
00405         KMessageBox::sorry( this, i18n( "A field with the same name already exists, please choose another one." ) );
00406         return;
00407       }
00408 
00409     mFieldWidget->addField( dlg.identifier(), dlg.title(),
00410                             dlg.type(), dlg.isGlobal() );
00411 
00412     if ( dlg.isGlobal() ) {
00413       KABPrefs::instance()->setGlobalCustomFields( marshallFields( true ) );
00414     } else {
00415       AddresseeConfig addrConfig( mAddressee );
00416       addrConfig.setCustomFields( marshallFields( false ) );
00417     }
00418 
00419     mRemoveButton->setEnabled( true );
00420   }
00421 }
00422 
00423 void CustomFieldsWidget::removeField()
00424 {
00425   const FieldRecordList list = mFieldWidget->fields();
00426 
00427   QStringList fields;
00428 
00429   FieldRecordList::ConstIterator it;
00430   for ( it = list.begin(); it != list.end(); ++it )
00431     fields.append( (*it).mTitle );
00432 
00433   bool ok;
00434   QString title = KInputDialog::getItem( i18n( "Remove Field" ),
00435                                          i18n( "Select the field you want to remove:" ),
00436                                          fields, 0, false, &ok, this );
00437 
00438   if ( ok ) {
00439     for ( it = list.begin(); it != list.end(); ++it )
00440       if ( (*it).mTitle == title ) {
00441         mFieldWidget->removeField( (*it).mIdentifier );
00442 
00443         if ( list.count() == 1 )
00444           mRemoveButton->setEnabled( false );
00445 
00446         if ( (*it).mGlobal ) {
00447           KABPrefs::instance()->setGlobalCustomFields( marshallFields( true ) );
00448         } else {
00449           AddresseeConfig addrConfig( mAddressee );
00450           addrConfig.setCustomFields( marshallFields( false ) );
00451         }
00452 
00453         return;
00454       }
00455   }
00456 }
00457 
00458 void CustomFieldsWidget::initGUI()
00459 {
00460   QGridLayout *layout = new QGridLayout( this, 2, 3, KDialog::marginHint(),
00461                                          KDialog::spacingHint() );
00462 
00463   mFieldWidget = new FieldWidget( this );
00464   layout->addMultiCellWidget( mFieldWidget, 0, 0, 0, 2 );
00465 
00466   mAddButton = new QPushButton( i18n( "Add Field..." ), this );
00467   layout->addWidget( mAddButton, 1, 1, Qt::AlignRight );
00468 
00469   mRemoveButton = new QPushButton( i18n( "Remove Field..." ), this );
00470   mRemoveButton->setEnabled( false );
00471   layout->addWidget( mRemoveButton, 1, 2, Qt::AlignRight );
00472 
00473   // load global fields
00474   QStringList globalFields = KABPrefs::instance()->globalCustomFields();
00475 
00476   if ( globalFields.isEmpty() )
00477     return;
00478 
00479   for ( uint i = 0; i < globalFields.count(); i += 3 ) {
00480     mFieldWidget->addField( globalFields[ i ], globalFields[ i + 1 ],
00481                             globalFields[ i + 2 ] , true );
00482     mRemoveButton->setEnabled( true );
00483   }
00484 }
00485 
00486 QStringList CustomFieldsWidget::marshallFields( bool global ) const
00487 {
00488   QStringList retval;
00489 
00490   const FieldRecordList list = mFieldWidget->fields();
00491   FieldRecordList::ConstIterator it;
00492   for ( it = list.begin(); it != list.end(); ++it ) {
00493     if ( (*it).mGlobal == global ) {
00494       retval.append( (*it).mIdentifier );
00495       retval.append( (*it).mTitle );
00496 
00497       QString type = "text";
00498       if ( (*it).mWidget->isA( "QSpinBox" ) ) {
00499         type = "integer";
00500       } else if ( (*it).mWidget->isA( "QCheckBox" ) ) {
00501         type = "boolean";
00502       } else if ( (*it).mWidget->isA( "QDateEdit" ) ) {
00503         type = "date";
00504       } else if ( (*it).mWidget->isA( "QTimeEdit" ) ) {
00505         type = "time";
00506       } else if ( (*it).mWidget->isA( "QDateTimeEdit" ) ) {
00507         type = "datetime";
00508       } else if ( (*it).mWidget->isA( "QLineEdit" ) ) {
00509         type = "text";
00510       }
00511 
00512       retval.append( type );
00513     }
00514   }
00515 
00516   return retval;
00517 }
00518 
00519 
00520 void splitField( const QString &str, QString &app, QString &name, QString &value )
00521 {
00522   int colon = str.find( ':' );
00523   if ( colon != -1 ) {
00524     QString tmp = str.left( colon );
00525     value = str.mid( colon + 1 );
00526 
00527     int dash = tmp.find( '-' );
00528     if ( dash != -1 ) {
00529       app = tmp.left( dash );
00530       name = tmp.mid( dash + 1 );
00531     }
00532   }
00533 }
00534 
00535 #include "customfieldswidget.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys