kaddressbook

customfieldswidget.cpp
1/*
2 This file is part of KAddressbook.
3 Copyright (c) 2004 Tobias Koenig <tokoe@kde.org>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
19 As a special exception, permission is given to link this program
20 with any edition of TQt, and distribute the resulting executable,
21 without including the source code for TQt in the source distribution.
22*/
23
24#include <tqcheckbox.h>
25#include <tqdatetimeedit.h>
26#include <tqframe.h>
27#include <tqlabel.h>
28#include <tqlayout.h>
29#include <tqpushbutton.h>
30#include <tqvalidator.h>
31#include <tqspinbox.h>
32
33#include <tdeaccelmanager.h>
34#include <kcombobox.h>
35#include <kinputdialog.h>
36#include <klineedit.h>
37#include <tdemessagebox.h>
38
39#include "addresseeconfig.h"
40#include "kabprefs.h"
41
42#include "customfieldswidget.h"
43
44
45AddFieldDialog::AddFieldDialog( TQWidget *parent, const char *name )
46 : KDialogBase( Plain, i18n( "Add Field" ), Ok | Cancel,
47 Ok, parent, name, true, true )
48{
49 TQWidget *page = plainPage();
50
51 TQGridLayout *layout = new TQGridLayout( page, 3, 2, marginHint(), spacingHint() );
52
53 TQLabel *label = new TQLabel( i18n( "Title:" ), page );
54 layout->addWidget( label, 0, 0 );
55
56 mTitle = new KLineEdit( page );
57 mTitle->setValidator( new TQRegExpValidator( TQRegExp( "([a-zA-Z]|\\d|-)+" ), mTitle ) );
58 label->setBuddy( mTitle );
59 layout->addWidget( mTitle, 0, 1 );
60
61 label = new TQLabel( i18n( "Type:" ), page );
62 layout->addWidget( label, 1, 0 );
63
64 mType = new KComboBox( page );
65 label->setBuddy( mType );
66 layout->addWidget( mType, 1, 1 );
67
68 mGlobal = new TQCheckBox( i18n( "Is available for all contacts" ), page );
69 mGlobal->setChecked( true );
70 layout->addMultiCellWidget( mGlobal, 2, 2, 0, 1 );
71
72 connect( mTitle, TQ_SIGNAL( textChanged( const TQString& ) ),
73 this, TQ_SLOT( nameChanged( const TQString& ) ) );
74
75 TDEAcceleratorManager::manage( this );
76
77 mTypeList.append( "text" );
78 mTypeName.append( i18n( "Text" ) );
79 mTypeList.append( "integer" );
80 mTypeName.append( i18n( "Numeric Value" ) );
81 mTypeList.append( "boolean" );
82 mTypeName.append( i18n( "Boolean" ) );
83 mTypeList.append( "date" );
84 mTypeName.append( i18n( "Date" ) );
85 mTypeList.append( "time" );
86 mTypeName.append( i18n( "Time" ) );
87 mTypeList.append( "datetime" );
88 mTypeName.append( i18n( "Date & Time" ) );
89
90 for ( uint i = 0; i < mTypeName.count(); ++i )
91 mType->insertItem( mTypeName[ i ] );
92
93 nameChanged( "" );
94
95 mTitle->setFocus();
96}
97
98TQString AddFieldDialog::title() const
99{
100 return mTitle->text();
101}
102
103TQString AddFieldDialog::identifier() const
104{
105 TQString id = mTitle->text().lower();
106 return id.replace( ",", "_" ).replace( " ", "_" );
107}
108
109TQString AddFieldDialog::type() const
110{
111 return mTypeList[ mType->currentItem() ];
112}
113
114bool AddFieldDialog::isGlobal() const
115{
116 return mGlobal->isChecked();
117}
118
119void AddFieldDialog::nameChanged( const TQString &name )
120{
121 enableButton( Ok, !name.isEmpty() );
122}
123
124FieldWidget::FieldWidget( TQWidget *parent, const char *name )
125 : TQWidget( parent, name )
126{
127 TQVBoxLayout *layout = new TQVBoxLayout( this, KDialog::marginHint(),
128 KDialog::spacingHint() );
129
130 mGlobalLayout = new TQVBoxLayout( layout, KDialog::spacingHint() );
131 mGlobalLayout->setAlignment( TQt::AlignTop );
132
133 mSeparator = new TQFrame( this );
134 mSeparator->setFrameStyle( TQFrame::HLine | TQFrame::Sunken );
135 mSeparator->hide();
136 layout->addWidget( mSeparator );
137
138 mLocalLayout = new TQVBoxLayout( layout, KDialog::spacingHint() );
139 mLocalLayout->setAlignment( TQt::AlignTop );
140}
141
142void FieldWidget::addField( const TQString &identifier, const TQString &title,
143 const TQString &type, bool isGlobal )
144{
145 FieldRecord record;
146
147 record.mIdentifier = identifier;
148 record.mTitle = title;
149 record.mLabel = new TQLabel( title + ":", this );
150 record.mGlobal = isGlobal;
151 if ( type == "integer" ) {
152 TQSpinBox *wdg = new TQSpinBox( 0, 1000, 1, this );
153 record.mWidget = wdg;
154 connect( wdg, TQ_SIGNAL( valueChanged( int ) ),
155 this, TQ_SIGNAL( changed() ) );
156 } else if ( type == "boolean" ) {
157 TQCheckBox *wdg = new TQCheckBox( this );
158 record.mWidget = wdg;
159 connect( wdg, TQ_SIGNAL( toggled( bool ) ),
160 this, TQ_SIGNAL( changed() ) );
161 } else if ( type == "date" ) {
162 TQDateEdit *wdg = new TQDateEdit( this );
163 record.mWidget = wdg;
164 connect( wdg, TQ_SIGNAL( valueChanged( const TQDate& ) ),
165 this, TQ_SIGNAL( changed() ) );
166 } else if ( type == "time" ) {
167 TQTimeEdit *wdg = new TQTimeEdit( this );
168 record.mWidget = wdg;
169 connect( wdg, TQ_SIGNAL( valueChanged( const TQTime& ) ),
170 this, TQ_SIGNAL( changed() ) );
171 } else if ( type == "datetime" ) {
172 TQDateTimeEdit *wdg = new TQDateTimeEdit( this );
173 record.mWidget = wdg;
174 connect( wdg, TQ_SIGNAL( valueChanged( const TQDateTime& ) ),
175 this, TQ_SIGNAL( changed() ) );
176 } else if ( type == "text" ) {
177 TQLineEdit *wdg = new TQLineEdit( this );
178 record.mWidget = wdg;
179 connect( wdg, TQ_SIGNAL( textChanged( const TQString& ) ),
180 this, TQ_SIGNAL( changed() ) );
181 }
182
183 record.mLabel->show();
184 record.mWidget->show();
185
186 if ( isGlobal ) {
187 record.mLayout = new TQHBoxLayout( mGlobalLayout );
188 record.mLayout->addWidget( record.mLabel );
189 record.mLayout->addWidget( record.mWidget, TQt::AlignLeft );
190 } else {
191 record.mLayout = new TQHBoxLayout( mLocalLayout );
192 record.mLayout->addWidget( record.mLabel );
193 record.mLayout->addWidget( record.mWidget, TQt::AlignLeft );
194 mSeparator->show();
195 }
196
197 mFieldList.append( record );
198
199 recalculateLayout();
200}
201
202void FieldWidget::removeField( const TQString &identifier )
203{
204 FieldRecordList::Iterator it;
205 for ( it = mFieldList.begin(); it != mFieldList.end(); ++it ) {
206 if ( (*it).mIdentifier == identifier ) {
207 delete (*it).mLabel;
208 delete (*it).mWidget;
209 delete (*it).mLayout;
210
211 mFieldList.remove( it );
212 recalculateLayout();
213
214 bool hasLocal = false;
215 for ( it = mFieldList.begin(); it != mFieldList.end(); ++it )
216 hasLocal = hasLocal || !(*it).mGlobal;
217
218 if ( !hasLocal )
219 mSeparator->hide();
220
221 return;
222 }
223 }
224}
225
226void FieldWidget::clearFields()
227{
228 FieldRecordList::ConstIterator fieldIt;
229 for ( fieldIt = mFieldList.begin(); fieldIt != mFieldList.end(); ++fieldIt ) {
230 if ( (*fieldIt).mWidget->isA( "TQLineEdit" ) ) {
231 TQLineEdit *wdg = static_cast<TQLineEdit*>( (*fieldIt).mWidget );
232 wdg->setText( TQString() );
233 } else if ( (*fieldIt).mWidget->isA( "TQSpinBox" ) ) {
234 TQSpinBox *wdg = static_cast<TQSpinBox*>( (*fieldIt).mWidget );
235 wdg->setValue( 0 );
236 } else if ( (*fieldIt).mWidget->isA( "TQCheckBox" ) ) {
237 TQCheckBox *wdg = static_cast<TQCheckBox*>( (*fieldIt).mWidget );
238 wdg->setChecked( true );
239 } else if ( (*fieldIt).mWidget->isA( "TQDateEdit" ) ) {
240 TQDateEdit *wdg = static_cast<TQDateEdit*>( (*fieldIt).mWidget );
241 wdg->setDate( TQDate::currentDate() );
242 } else if ( (*fieldIt).mWidget->isA( "TQTimeEdit" ) ) {
243 TQTimeEdit *wdg = static_cast<TQTimeEdit*>( (*fieldIt).mWidget );
244 wdg->setTime( TQTime::currentTime() );
245 } else if ( (*fieldIt).mWidget->isA( "TQDateTimeEdit" ) ) {
246 TQDateTimeEdit *wdg = static_cast<TQDateTimeEdit*>( (*fieldIt).mWidget );
247 wdg->setDateTime( TQDateTime::currentDateTime() );
248 }
249 }
250}
251
252void FieldWidget::loadContact( TDEABC::Addressee *addr )
253{
254 const TQStringList customs = addr->customs();
255
256 clearFields();
257
258 TQStringList::ConstIterator it;
259 for ( it = customs.begin(); it != customs.end(); ++it ) {
260 TQString app, name, value;
261 splitField( *it, app, name, value );
262 if ( app != "KADDRESSBOOK" )
263 continue;
264
265 FieldRecordList::ConstIterator fieldIt;
266 for ( fieldIt = mFieldList.begin(); fieldIt != mFieldList.end(); ++fieldIt ) {
267 if ( (*fieldIt).mIdentifier == name ) {
268 if ( (*fieldIt).mWidget->isA( "TQLineEdit" ) ) {
269 TQLineEdit *wdg = static_cast<TQLineEdit*>( (*fieldIt).mWidget );
270 wdg->setText( value );
271 } else if ( (*fieldIt).mWidget->isA( "TQSpinBox" ) ) {
272 TQSpinBox *wdg = static_cast<TQSpinBox*>( (*fieldIt).mWidget );
273 wdg->setValue( value.toInt() );
274 } else if ( (*fieldIt).mWidget->isA( "TQCheckBox" ) ) {
275 TQCheckBox *wdg = static_cast<TQCheckBox*>( (*fieldIt).mWidget );
276 wdg->setChecked( value == "true" || value == "1" );
277 } else if ( (*fieldIt).mWidget->isA( "TQDateEdit" ) ) {
278 TQDateEdit *wdg = static_cast<TQDateEdit*>( (*fieldIt).mWidget );
279 wdg->setDate( TQDate::fromString( value, TQt::ISODate ) );
280 } else if ( (*fieldIt).mWidget->isA( "TQTimeEdit" ) ) {
281 TQTimeEdit *wdg = static_cast<TQTimeEdit*>( (*fieldIt).mWidget );
282 wdg->setTime( TQTime::fromString( value, TQt::ISODate ) );
283 } else if ( (*fieldIt).mWidget->isA( "TQDateTimeEdit" ) ) {
284 TQDateTimeEdit *wdg = static_cast<TQDateTimeEdit*>( (*fieldIt).mWidget );
285 wdg->setDateTime( TQDateTime::fromString( value, TQt::ISODate ) );
286 }
287 }
288 }
289 }
290}
291
292void FieldWidget::setReadOnly( bool readOnly )
293{
294 FieldRecordList::ConstIterator it;
295 for ( it = mFieldList.begin(); it != mFieldList.end(); ++it ) {
296 TQString value;
297 if ( (*it).mWidget->isA( "TQLineEdit" ) ) {
298 TQLineEdit *wdg = static_cast<TQLineEdit*>( (*it).mWidget );
299 wdg->setReadOnly(readOnly);
300 } else if ( (*it).mWidget->isA( "TQSpinBox" ) ) {
301 TQSpinBox *wdg = static_cast<TQSpinBox*>( (*it).mWidget );
302 wdg->setEnabled( !readOnly );
303 } else if ( (*it).mWidget->isA( "TQCheckBox" ) ) {
304 TQCheckBox *wdg = static_cast<TQCheckBox*>( (*it).mWidget );
305 wdg->setEnabled( !readOnly );
306 } else if ( (*it).mWidget->isA( "TQDateEdit" ) ) {
307 TQDateEdit *wdg = static_cast<TQDateEdit*>( (*it).mWidget );
308 wdg->setEnabled( !readOnly );
309 } else if ( (*it).mWidget->isA( "TQTimeEdit" ) ) {
310 TQTimeEdit *wdg = static_cast<TQTimeEdit*>( (*it).mWidget );
311 wdg->setEnabled( !readOnly );
312 } else if ( (*it).mWidget->isA( "TQDateTimeEdit" ) ) {
313 TQDateTimeEdit *wdg = static_cast<TQDateTimeEdit*>( (*it).mWidget );
314 wdg->setEnabled( !readOnly );
315 }
316 }
317}
318
319void FieldWidget::storeContact( TDEABC::Addressee *addr )
320{
321 FieldRecordList::ConstIterator it;
322 for ( it = mFieldList.begin(); it != mFieldList.end(); ++it ) {
323 TQString value;
324 if ( (*it).mWidget->isA( "TQLineEdit" ) ) {
325 TQLineEdit *wdg = static_cast<TQLineEdit*>( (*it).mWidget );
326 value = wdg->text();
327 } else if ( (*it).mWidget->isA( "TQSpinBox" ) ) {
328 TQSpinBox *wdg = static_cast<TQSpinBox*>( (*it).mWidget );
329 value = TQString::number( wdg->value() );
330 } else if ( (*it).mWidget->isA( "TQCheckBox" ) ) {
331 TQCheckBox *wdg = static_cast<TQCheckBox*>( (*it).mWidget );
332 value = ( wdg->isChecked() ? "true" : "false" );
333 } else if ( (*it).mWidget->isA( "TQDateEdit" ) ) {
334 TQDateEdit *wdg = static_cast<TQDateEdit*>( (*it).mWidget );
335 value = wdg->date().toString( TQt::ISODate );
336 } else if ( (*it).mWidget->isA( "TQTimeEdit" ) ) {
337 TQTimeEdit *wdg = static_cast<TQTimeEdit*>( (*it).mWidget );
338 value = wdg->time().toString( TQt::ISODate );
339 } else if ( (*it).mWidget->isA( "TQDateTimeEdit" ) ) {
340 TQDateTimeEdit *wdg = static_cast<TQDateTimeEdit*>( (*it).mWidget );
341 value = wdg->dateTime().toString( TQt::ISODate );
342 }
343
344 if ( value.isEmpty() )
345 addr->removeCustom( "KADDRESSBOOK", (*it).mIdentifier );
346 else
347 addr->insertCustom( "KADDRESSBOOK", (*it).mIdentifier, value );
348 }
349}
350
351void FieldWidget::removeLocalFields()
352{
353 FieldRecordList::Iterator it;
354 for ( it = mFieldList.begin(); it != mFieldList.end(); ++it ) {
355 if ( !(*it).mGlobal ) {
356 delete (*it).mLabel;
357 delete (*it).mWidget;
358 delete (*it).mLayout;
359
360 it = mFieldList.remove( it );
361 it--;
362 recalculateLayout();
363 }
364 }
365}
366
367void FieldWidget::recalculateLayout()
368{
369 int maxWidth = 0;
370
371 FieldRecordList::ConstIterator it;
372 for ( it = mFieldList.begin(); it != mFieldList.end(); ++it )
373 maxWidth = TQMAX( maxWidth, (*it).mLabel->minimumSizeHint().width() );
374
375 for ( it = mFieldList.begin(); it != mFieldList.end(); ++it )
376 (*it).mLabel->setMinimumWidth( maxWidth );
377}
378
379CustomFieldsWidget::CustomFieldsWidget( TDEABC::AddressBook *ab,
380 TQWidget *parent, const char *name )
381 : KAB::ContactEditorWidget( ab, parent, name )
382{
383 initGUI();
384
385 connect( mAddButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( addField() ) );
386 connect( mRemoveButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( removeField() ) );
387
388 connect( mFieldWidget, TQ_SIGNAL( changed() ), this, TQ_SLOT( setModified() ) );
389}
390
391void CustomFieldsWidget::loadContact( TDEABC::Addressee *addr )
392{
393 mAddressee = *addr;
394
395 mFieldWidget->removeLocalFields();
396
397 AddresseeConfig addrConfig( mAddressee );
398 TQStringList fields = addrConfig.customFields();
399
400 if ( !fields.isEmpty() ) {
401 for ( uint i = 0; i < fields.count(); i += 3 ) {
402 mFieldWidget->addField( fields[ i ], fields[ i + 1 ],
403 fields[ i + 2 ] , false );
404 mRemoveButton->setEnabled( true );
405 }
406 }
407
408 mFieldWidget->loadContact( addr );
409}
410
411void CustomFieldsWidget::storeContact( TDEABC::Addressee *addr )
412{
413 mFieldWidget->storeContact( addr );
414}
415
416void CustomFieldsWidget::setReadOnly( bool readOnly )
417{
418 mAddButton->setEnabled( !readOnly );
419 mRemoveButton->setEnabled( !readOnly && !mFieldWidget->fields().isEmpty() );
420 mFieldWidget->setReadOnly( readOnly );
421}
422
423void CustomFieldsWidget::addField()
424{
425 AddFieldDialog dlg( this );
426
427 if ( dlg.exec() ) {
428 FieldRecordList list = mFieldWidget->fields();
429
430 FieldRecordList::ConstIterator it;
431 for ( it = list.begin(); it != list.end(); ++it )
432 if ( (*it).mIdentifier == dlg.identifier() ) {
433 KMessageBox::sorry( this, i18n( "A field with the same name already exists, please choose another one." ) );
434 return;
435 }
436
437 mFieldWidget->addField( dlg.identifier(), dlg.title(),
438 dlg.type(), dlg.isGlobal() );
439
440 if ( dlg.isGlobal() ) {
441 KABPrefs::instance()->setGlobalCustomFields( marshallFields( true ) );
442 } else {
443 AddresseeConfig addrConfig( mAddressee );
444 addrConfig.setCustomFields( marshallFields( false ) );
445 }
446
447 mRemoveButton->setEnabled( true );
448 }
449}
450
451void CustomFieldsWidget::removeField()
452{
453 const FieldRecordList list = mFieldWidget->fields();
454
455 TQStringList fields;
456
457 FieldRecordList::ConstIterator it;
458 for ( it = list.begin(); it != list.end(); ++it )
459 fields.append( (*it).mTitle );
460
461 bool ok;
462 TQString title = KInputDialog::getItem( i18n( "Remove Field" ),
463 i18n( "Select the field you want to remove:" ),
464 fields, 0, false, &ok, this );
465
466 if ( ok ) {
467 for ( it = list.begin(); it != list.end(); ++it )
468 if ( (*it).mTitle == title ) {
469 mFieldWidget->removeField( (*it).mIdentifier );
470
471 if ( list.count() == 1 )
472 mRemoveButton->setEnabled( false );
473
474 if ( (*it).mGlobal ) {
475 KABPrefs::instance()->setGlobalCustomFields( marshallFields( true ) );
476 } else {
477 AddresseeConfig addrConfig( mAddressee );
478 addrConfig.setCustomFields( marshallFields( false ) );
479 }
480
481 return;
482 }
483 }
484}
485
486void CustomFieldsWidget::initGUI()
487{
488 TQGridLayout *layout = new TQGridLayout( this, 2, 3, KDialog::marginHint(),
489 KDialog::spacingHint() );
490
491 mFieldWidget = new FieldWidget( this );
492 layout->addMultiCellWidget( mFieldWidget, 0, 0, 0, 2 );
493
494 mAddButton = new TQPushButton( i18n( "Add Field..." ), this );
495 layout->addWidget( mAddButton, 1, 1, TQt::AlignRight );
496
497 mRemoveButton = new TQPushButton( i18n( "Remove Field..." ), this );
498 mRemoveButton->setEnabled( false );
499 layout->addWidget( mRemoveButton, 1, 2, TQt::AlignRight );
500
501 // load global fields
502 TQStringList globalFields = KABPrefs::instance()->globalCustomFields();
503
504 if ( globalFields.isEmpty() )
505 return;
506
507 for ( uint i = 0; i < globalFields.count(); i += 3 ) {
508 mFieldWidget->addField( globalFields[ i ], globalFields[ i + 1 ],
509 globalFields[ i + 2 ] , true );
510 mRemoveButton->setEnabled( true );
511 }
512}
513
514TQStringList CustomFieldsWidget::marshallFields( bool global ) const
515{
516 TQStringList retval;
517
518 const FieldRecordList list = mFieldWidget->fields();
519 FieldRecordList::ConstIterator it;
520 for ( it = list.begin(); it != list.end(); ++it ) {
521 if ( (*it).mGlobal == global ) {
522 retval.append( (*it).mIdentifier );
523 retval.append( (*it).mTitle );
524
525 TQString type = "text";
526 if ( (*it).mWidget->isA( "TQSpinBox" ) ) {
527 type = "integer";
528 } else if ( (*it).mWidget->isA( "TQCheckBox" ) ) {
529 type = "boolean";
530 } else if ( (*it).mWidget->isA( "TQDateEdit" ) ) {
531 type = "date";
532 } else if ( (*it).mWidget->isA( "TQTimeEdit" ) ) {
533 type = "time";
534 } else if ( (*it).mWidget->isA( "TQDateTimeEdit" ) ) {
535 type = "datetime";
536 } else if ( (*it).mWidget->isA( "TQLineEdit" ) ) {
537 type = "text";
538 }
539
540 retval.append( type );
541 }
542 }
543
544 return retval;
545}
546
547
548void splitField( const TQString &str, TQString &app, TQString &name, TQString &value )
549{
550 int colon = str.find( ':' );
551 if ( colon != -1 ) {
552 TQString tmp = str.left( colon );
553 value = str.mid( colon + 1 );
554
555 int dash = tmp.find( '-' );
556 if ( dash != -1 ) {
557 app = tmp.left( dash );
558 name = tmp.mid( dash + 1 );
559 }
560 }
561}
562
563#include "customfieldswidget.moc"