1 | /* |
2 | This file is part of libkresources. |
3 | |
4 | Copyright (c) 2002 Tobias Koenig <tokoe@kde.org> |
5 | Copyright (c) 2002 Jan-Pascal van Best <janpascal@vanbest.org> |
6 | Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> |
7 | |
8 | This library is free software; you can redistribute it and/or |
9 | modify it under the terms of the GNU Library General Public |
10 | License as published by the Free Software Foundation; either |
11 | version 2 of the License, or (at your option) any later version. |
12 | |
13 | This library is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | Library General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU Library General Public License |
19 | along with this library; see the file COPYING.LIB. If not, write to |
20 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
21 | Boston, MA 02110-1301, USA. |
22 | */ |
23 | /** |
24 | @file |
25 | This file is part of the KDE resource framework and defines the |
26 | ConfigPage class. |
27 | |
28 | @brief |
29 | A resource configuration page. |
30 | |
31 | @author Tobias Koenig |
32 | @author Jan-Pascal van Best |
33 | @author Cornelius Schumacher |
34 | */ |
35 | |
36 | #include "configpage.h" |
37 | |
38 | #include <QGroupBox> |
39 | #include <QLabel> |
40 | #include <QLayout> |
41 | #include <QTreeWidget> |
42 | #include <QTreeWidgetItem> |
43 | |
44 | #include <kcombobox.h> |
45 | #include <kdebug.h> |
46 | #include <klocalizedstring.h> |
47 | #include <kmessagebox.h> |
48 | #include <kconfig.h> |
49 | #include <kstandarddirs.h> |
50 | #include <kurlrequester.h> |
51 | #include <kdialogbuttonbox.h> |
52 | #include <kservicetypetrader.h> |
53 | #include <kinputdialog.h> |
54 | #include <QtCore/QList> |
55 | |
56 | #include "resource.h" |
57 | #include "configdialog.h" |
58 | |
59 | namespace KRES { |
60 | |
61 | class ResourcePageInfo::Private |
62 | { |
63 | }; |
64 | |
65 | ResourcePageInfo::ResourcePageInfo() : d( new KRES::ResourcePageInfo::Private ) |
66 | { |
67 | mManager = 0; |
68 | mConfig = 0; |
69 | } |
70 | |
71 | ResourcePageInfo::~ResourcePageInfo() |
72 | { |
73 | //delete mManager; |
74 | mManager = 0; |
75 | //delete mConfig; |
76 | mConfig = 0; |
77 | delete d; |
78 | } |
79 | |
80 | class ConfigViewItem : public QTreeWidgetItem |
81 | { |
82 | public: |
83 | ConfigViewItem( QTreeWidget *parent, Resource *resource ) : |
84 | QTreeWidgetItem( parent ), mResource( resource ), mIsStandard( false ) |
85 | { |
86 | updateItem(); |
87 | } |
88 | |
89 | void setStandard( bool value ) |
90 | { |
91 | setText( 2, ( value ? i18nc( "yes, a standard resource" , "Yes" ) : QString() ) ); |
92 | mIsStandard = value; |
93 | } |
94 | |
95 | bool standard() const { return mIsStandard; } |
96 | bool readOnly() const { return mResource->readOnly(); } |
97 | |
98 | Resource *resource() { return mResource; } |
99 | |
100 | void updateItem() |
101 | { |
102 | setCheckState( 0, mResource->isActive() ? Qt::Checked : Qt::Unchecked ); |
103 | setText( 0, mResource->resourceName() ); |
104 | setText( 1, mResource->type() ); |
105 | setText( 2, mIsStandard ? i18nc( "yes, a standard resource" , "Yes" ) : QString() ); |
106 | } |
107 | |
108 | bool isOn() |
109 | { |
110 | return checkState( 0 ) == Qt::Checked; |
111 | } |
112 | |
113 | private: |
114 | Resource *mResource; |
115 | bool mIsStandard; |
116 | }; |
117 | |
118 | class ConfigPage::Private |
119 | { |
120 | public: |
121 | void loadManager( const QString &family, ConfigPage *page ); |
122 | void saveResourceSettings( ConfigPage *page ); |
123 | |
124 | Manager<Resource> *mCurrentManager; |
125 | KConfig *mCurrentConfig; |
126 | KConfigGroup *mConfigGroup; |
127 | QString mFamily; |
128 | QStringList mFamilyMap; |
129 | QList<KSharedPtr<ResourcePageInfo> > mInfoMap; |
130 | |
131 | KComboBox *mFamilyCombo; |
132 | QTreeWidget *mListView; |
133 | QPushButton *mAddButton; |
134 | QPushButton *mRemoveButton; |
135 | QPushButton *mEditButton; |
136 | QPushButton *mStandardButton; |
137 | |
138 | QTreeWidgetItem *mLastItem; |
139 | }; |
140 | |
141 | ConfigPage::ConfigPage( QWidget *parent ) |
142 | : QWidget( parent ), d( new KRES::ConfigPage::Private ) |
143 | { |
144 | setWindowTitle( i18n( "Resource Configuration" ) ); |
145 | |
146 | QVBoxLayout *mainLayout = new QVBoxLayout( this ); |
147 | mainLayout->setMargin( 0 ); |
148 | |
149 | QGroupBox *groupBox = new QGroupBox( i18n( "Resources" ), this ); |
150 | QGridLayout *groupBoxLayout = new QGridLayout(); |
151 | groupBox->setLayout( groupBoxLayout ); |
152 | |
153 | d->mFamilyCombo = new KComboBox( false, groupBox ); |
154 | groupBoxLayout->addWidget( d->mFamilyCombo, 0, 0, 1, 2 ); |
155 | |
156 | d->mCurrentManager = 0; |
157 | d->mCurrentConfig = 0; |
158 | d->mListView = new QTreeWidget( groupBox ); |
159 | d->mListView->setColumnCount( 3 ); |
160 | QStringList ; |
161 | headerLabels << i18nc( "@title:column resource name" , "Name" ) |
162 | << i18nc( "@title:column resource type" , "Type" ) |
163 | << i18nc( "@title:column a standard resource?" , "Standard" ); |
164 | d->mListView->setHeaderItem( new QTreeWidgetItem( headerLabels ) ); |
165 | |
166 | groupBoxLayout->addWidget( d->mListView, 1, 0 ); |
167 | connect( d->mListView, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), |
168 | this, SLOT(slotEdit()) ); |
169 | |
170 | KDialogButtonBox *buttonBox = new KDialogButtonBox( groupBox, Qt::Vertical ); |
171 | d->mAddButton = buttonBox->addButton( i18n( "&Add..." ), |
172 | KDialogButtonBox::ActionRole, |
173 | this, SLOT(slotAdd()) ); |
174 | |
175 | d->mRemoveButton = buttonBox->addButton( i18n( "&Remove" ), |
176 | KDialogButtonBox::ActionRole, |
177 | this, SLOT(slotRemove()) ); |
178 | d->mRemoveButton->setEnabled( false ); |
179 | |
180 | d->mEditButton = buttonBox->addButton( i18n( "&Edit..." ), |
181 | KDialogButtonBox::ActionRole, |
182 | this, SLOT(slotEdit()) ); |
183 | d->mEditButton->setEnabled( false ); |
184 | |
185 | d->mStandardButton = buttonBox->addButton( i18n( "&Use as Standard" ), |
186 | KDialogButtonBox::ActionRole, |
187 | this, SLOT(slotStandard()) ); |
188 | d->mStandardButton->setEnabled( false ); |
189 | |
190 | buttonBox->layout(); |
191 | groupBoxLayout->addWidget( buttonBox, 1, 1 ); |
192 | |
193 | mainLayout->addWidget( groupBox ); |
194 | |
195 | connect( d->mFamilyCombo, SIGNAL(activated(int)), |
196 | SLOT(slotFamilyChanged(int)) ); |
197 | connect( d->mListView, SIGNAL(itemSelectionChanged()), |
198 | SLOT(slotSelectionChanged()) ); |
199 | connect( d->mListView, SIGNAL(itemClicked(QTreeWidgetItem*,int)), |
200 | SLOT(slotItemClicked(QTreeWidgetItem*)) ); |
201 | |
202 | d->mLastItem = 0; |
203 | |
204 | d->mConfigGroup = new KConfigGroup( new KConfig( QLatin1String("kcmkresourcesrc" ) ), "General" ); |
205 | |
206 | load(); |
207 | } |
208 | |
209 | ConfigPage::~ConfigPage() |
210 | { |
211 | QList<KSharedPtr<ResourcePageInfo> >::Iterator it; |
212 | for ( it = d->mInfoMap.begin(); it != d->mInfoMap.end(); ++it ) { |
213 | ( *it )->mManager->removeObserver( this ); |
214 | } |
215 | |
216 | d->mConfigGroup->writeEntry( "CurrentFamily" , d->mFamilyCombo->currentIndex() ); |
217 | delete d->mConfigGroup->config(); |
218 | delete d->mConfigGroup; |
219 | d->mConfigGroup = 0; |
220 | delete d; |
221 | } |
222 | |
223 | void ConfigPage::load() |
224 | { |
225 | kDebug(); |
226 | |
227 | d->mListView->clear(); |
228 | d->mFamilyMap.clear(); |
229 | d->mInfoMap.clear(); |
230 | QStringList familyDisplayNames; |
231 | |
232 | // KDE-3.3 compatibility code: get families from the plugins |
233 | QStringList compatFamilyNames; |
234 | const KService::List plugins = KServiceTypeTrader::self()->query( QLatin1String("KResources/Plugin" ) ); |
235 | KService::List::ConstIterator it = plugins.begin(); |
236 | KService::List::ConstIterator end = plugins.end(); |
237 | for ( ; it != end; ++it ) { |
238 | const QString family = ( *it )->property( QLatin1String("X-KDE-ResourceFamily" ) ).toString(); |
239 | if ( compatFamilyNames.indexOf( family ) == -1 ) { |
240 | compatFamilyNames.append( family ); |
241 | } |
242 | } |
243 | |
244 | const KService::List managers = KServiceTypeTrader::self()->query( QLatin1String("KResources/Manager" ) ); |
245 | KService::List::ConstIterator m_it; |
246 | for ( m_it = managers.begin(); m_it != managers.end(); ++m_it ) { |
247 | QString displayName = ( *m_it )->property( QLatin1String("Name" ) ).toString(); |
248 | familyDisplayNames.append( displayName ); |
249 | QString family = ( *m_it )->property( QLatin1String("X-KDE-ResourceFamily" ) ).toString(); |
250 | if ( !family.isEmpty() ) { |
251 | compatFamilyNames.removeAll( family ); |
252 | d->mFamilyMap.append( family ); |
253 | kDebug() << "Loading manager for family " << family; |
254 | d->loadManager( family, this ); |
255 | kDebug() << "Manager for family " << family << " loaded." ; |
256 | } |
257 | } |
258 | |
259 | // Rest of the kde-3.3 compat code |
260 | QStringList::ConstIterator cfit = compatFamilyNames.constBegin(); |
261 | for ( ; cfit != compatFamilyNames.constEnd(); ++cfit ) { |
262 | d->mFamilyMap.append( *cfit ); |
263 | familyDisplayNames.append( *cfit ); |
264 | d->loadManager( *cfit, this ); |
265 | } |
266 | |
267 | d->mCurrentManager = 0; |
268 | |
269 | d->mFamilyCombo->clear(); |
270 | d->mFamilyCombo->insertItems( 0, familyDisplayNames ); |
271 | |
272 | int currentFamily = d->mConfigGroup->readEntry( "CurrentFamily" , 0 ); |
273 | d->mFamilyCombo->setCurrentIndex( currentFamily ); |
274 | slotFamilyChanged( currentFamily ); |
275 | emit changed( false ); |
276 | } |
277 | |
278 | void ConfigPage::Private::loadManager( const QString &family, ConfigPage *page ) |
279 | { |
280 | mCurrentManager = new Manager<Resource>( family ); |
281 | if ( mCurrentManager ) { |
282 | mCurrentManager->addObserver( page ); |
283 | |
284 | ResourcePageInfo *info = new ResourcePageInfo; |
285 | info->mManager = mCurrentManager; |
286 | info->mConfig = new KConfig( KRES::ManagerImpl::defaultConfigFile( family ) ); |
287 | info->mManager->readConfig( info->mConfig ); |
288 | |
289 | mInfoMap.append( KSharedPtr<ResourcePageInfo>( info ) ); |
290 | } |
291 | } |
292 | |
293 | void ConfigPage::save() |
294 | { |
295 | d->saveResourceSettings( this ); |
296 | |
297 | QList<KSharedPtr<ResourcePageInfo> >::Iterator it; |
298 | for ( it = d->mInfoMap.begin(); it != d->mInfoMap.end(); ++it ) { |
299 | ( *it )->mManager->writeConfig( ( *it )->mConfig ); |
300 | } |
301 | |
302 | emit changed( false ); |
303 | } |
304 | |
305 | void ConfigPage::defaults() |
306 | { |
307 | } |
308 | |
309 | void ConfigPage::slotFamilyChanged( int pos ) |
310 | { |
311 | if ( pos < 0 || pos >= (int)d->mFamilyMap.count() ) { |
312 | return; |
313 | } |
314 | |
315 | d->saveResourceSettings( this ); |
316 | |
317 | d->mFamily = d->mFamilyMap[ pos ]; |
318 | |
319 | d->mCurrentManager = d->mInfoMap[ pos ]->mManager; |
320 | d->mCurrentConfig = d->mInfoMap[ pos ]->mConfig; |
321 | |
322 | if ( !d->mCurrentManager ) { |
323 | kDebug() << "ERROR: cannot create ResourceManager<Resource>( mFamily )" ; |
324 | } |
325 | |
326 | d->mListView->clear(); |
327 | |
328 | if ( d->mCurrentManager->isEmpty() ) { |
329 | defaults(); |
330 | } |
331 | |
332 | Resource *standardResource = d->mCurrentManager->standardResource(); |
333 | |
334 | Manager<Resource>::Iterator it; |
335 | for ( it = d->mCurrentManager->begin(); it != d->mCurrentManager->end(); ++it ) { |
336 | ConfigViewItem *item = new ConfigViewItem( d->mListView, *it ); |
337 | if ( *it == standardResource ) { |
338 | item->setStandard( true ); |
339 | } |
340 | } |
341 | |
342 | if ( d->mListView->topLevelItemCount() == 0 ) { |
343 | defaults(); |
344 | emit changed( true ); |
345 | d->mCurrentManager->writeConfig( d->mCurrentConfig ); |
346 | } else { |
347 | if ( !standardResource ) { |
348 | KMessageBox::sorry( this, i18n( "There is no standard resource. Please select one." ) ); |
349 | } |
350 | |
351 | emit changed( false ); |
352 | } |
353 | } |
354 | |
355 | void ConfigPage::slotAdd() |
356 | { |
357 | if ( !d->mCurrentManager ) { |
358 | return; |
359 | } |
360 | |
361 | QStringList types = d->mCurrentManager->resourceTypeNames(); |
362 | QStringList descs = d->mCurrentManager->resourceTypeDescriptions(); |
363 | bool ok = false; |
364 | QString desc = KInputDialog::getItem( i18n( "Resource Configuration" ), |
365 | i18n( "Please select type of the new resource:" ), descs, |
366 | 0, false, &ok, this ); |
367 | if ( !ok ) { |
368 | return; |
369 | } |
370 | |
371 | QString type = types[ descs.indexOf( desc ) ]; |
372 | |
373 | // Create new resource |
374 | Resource *resource = d->mCurrentManager->createResource( type ); |
375 | if ( !resource ) { |
376 | KMessageBox::error( |
377 | this, i18n( "Unable to create resource of type '%1'." , type ) ); |
378 | return; |
379 | } |
380 | |
381 | resource->setResourceName( type + QLatin1String("-resource" ) ); |
382 | |
383 | ConfigDialog dlg( this, d->mFamily, resource ); |
384 | |
385 | if ( dlg.exec() ) { //krazy:exclude=crashy |
386 | d->mCurrentManager->add( resource ); |
387 | |
388 | ConfigViewItem *item = new ConfigViewItem( d->mListView, resource ); |
389 | |
390 | d->mLastItem = item; |
391 | |
392 | // if there are only read-only resources we'll set this resource |
393 | // as standard resource |
394 | if ( !resource->readOnly() ) { |
395 | bool onlyReadOnly = true; |
396 | for ( int i = 0; i < d->mListView->topLevelItemCount(); ++i ) { |
397 | ConfigViewItem *confIt = static_cast<ConfigViewItem*>( d->mListView->topLevelItem( i ) ); |
398 | if ( !confIt->readOnly() && confIt != item ) { |
399 | onlyReadOnly = false; |
400 | } |
401 | } |
402 | |
403 | if ( onlyReadOnly ) { |
404 | item->setStandard( true ); |
405 | } |
406 | } |
407 | |
408 | emit changed( true ); |
409 | } else { |
410 | delete resource; |
411 | resource = 0; |
412 | } |
413 | } |
414 | |
415 | void ConfigPage::slotRemove() |
416 | { |
417 | if ( !d->mCurrentManager ) { |
418 | return; |
419 | } |
420 | |
421 | QTreeWidgetItem *item = d->mListView->currentItem(); |
422 | ConfigViewItem *confItem = static_cast<ConfigViewItem*>( item ); |
423 | |
424 | if ( !confItem ) { |
425 | return; |
426 | } |
427 | |
428 | if ( confItem->standard() ) { |
429 | KMessageBox::sorry( this, |
430 | i18n( "You cannot remove your standard resource. " |
431 | "Please select a new standard resource first." ) ); |
432 | return; |
433 | } |
434 | |
435 | d->mCurrentManager->remove( confItem->resource() ); |
436 | |
437 | if ( item == d->mLastItem ) { |
438 | d->mLastItem = 0; |
439 | } |
440 | |
441 | d->mListView->takeTopLevelItem( d->mListView->indexOfTopLevelItem( item ) ); |
442 | delete item; |
443 | |
444 | emit changed( true ); |
445 | } |
446 | |
447 | void ConfigPage::slotEdit() |
448 | { |
449 | if ( !d->mCurrentManager ) { |
450 | return; |
451 | } |
452 | |
453 | QTreeWidgetItem *item = d->mListView->currentItem(); |
454 | ConfigViewItem *configItem = static_cast<ConfigViewItem*>( item ); |
455 | if ( !configItem ) { |
456 | return; |
457 | } |
458 | |
459 | Resource *resource = configItem->resource(); |
460 | |
461 | ConfigDialog dlg( this, d->mFamily, resource ); |
462 | |
463 | if ( dlg.exec() ) { //krazy:exclude=crashy |
464 | configItem->setText( 0, resource->resourceName() ); |
465 | configItem->setText( 1, resource->type() ); |
466 | |
467 | if ( configItem->standard() && configItem->readOnly() ) { |
468 | KMessageBox::sorry( this, i18n( "You cannot use a read-only resource as standard." ) ); |
469 | configItem->setStandard( false ); |
470 | } |
471 | |
472 | d->mCurrentManager->change( resource ); |
473 | emit changed( true ); |
474 | } |
475 | } |
476 | |
477 | void ConfigPage::slotStandard() |
478 | { |
479 | if ( !d->mCurrentManager ) { |
480 | return; |
481 | } |
482 | |
483 | ConfigViewItem *item = static_cast<ConfigViewItem*>( d->mListView->currentItem() ); |
484 | if ( !item ) { |
485 | return; |
486 | } |
487 | |
488 | if ( item->readOnly() ) { |
489 | KMessageBox::sorry( this, i18n( "You cannot use a read-only resource as standard." ) ); |
490 | return; |
491 | } |
492 | |
493 | if ( !item->isOn() ) { |
494 | KMessageBox::sorry( this, i18n( "You cannot use an inactive resource as standard." ) ); |
495 | return; |
496 | } |
497 | |
498 | for ( int i = 0; i < d->mListView->topLevelItemCount(); ++i ) { |
499 | ConfigViewItem *configItem = static_cast<ConfigViewItem*>( d->mListView->topLevelItem( i ) ); |
500 | if ( configItem->standard() ) { |
501 | configItem->setStandard( false ); |
502 | } |
503 | } |
504 | |
505 | item->setStandard( true ); |
506 | d->mCurrentManager->setStandardResource( item->resource() ); |
507 | |
508 | emit changed( true ); |
509 | } |
510 | |
511 | void ConfigPage::slotSelectionChanged() |
512 | { |
513 | bool state = ( d->mListView->currentItem() != 0 ); |
514 | |
515 | d->mRemoveButton->setEnabled( state ); |
516 | d->mEditButton->setEnabled( state ); |
517 | d->mStandardButton->setEnabled( state ); |
518 | } |
519 | |
520 | void ConfigPage::resourceAdded( Resource *resource ) |
521 | { |
522 | kDebug() << resource->resourceName(); |
523 | |
524 | ConfigViewItem *item = new ConfigViewItem( d->mListView, resource ); |
525 | |
526 | item->setCheckState( 0, resource->isActive()? Qt::Checked : Qt::Unchecked ); |
527 | |
528 | d->mLastItem = item; |
529 | |
530 | emit changed( true ); |
531 | } |
532 | |
533 | void ConfigPage::resourceModified( Resource *resource ) |
534 | { |
535 | kDebug() << resource->resourceName(); |
536 | ConfigViewItem *item = findItem( resource ); |
537 | if ( !item ) { |
538 | return; |
539 | } |
540 | |
541 | // TODO: Reread resource config. Otherwise we won't see the modification. |
542 | |
543 | item->updateItem(); |
544 | } |
545 | |
546 | void ConfigPage::resourceDeleted( Resource *resource ) |
547 | { |
548 | kDebug() << resource->resourceName(); |
549 | |
550 | ConfigViewItem *item = findItem( resource ); |
551 | if ( !item ) { |
552 | return; |
553 | } |
554 | |
555 | delete item; |
556 | } |
557 | |
558 | ConfigViewItem *ConfigPage::findItem( Resource *resource ) |
559 | { |
560 | for ( int i = 0; i < d->mListView->topLevelItemCount(); ++i ) { |
561 | ConfigViewItem *item = static_cast<ConfigViewItem *>( d->mListView->topLevelItem( i ) ); |
562 | if ( item->resource() == resource ) { |
563 | return item; |
564 | } |
565 | } |
566 | return 0; |
567 | } |
568 | |
569 | void ConfigPage::slotItemClicked( QTreeWidgetItem *item ) |
570 | { |
571 | ConfigViewItem *configItem = static_cast<ConfigViewItem *>( item ); |
572 | if ( !configItem ) { |
573 | return; |
574 | } |
575 | |
576 | if ( configItem->standard() && !configItem->isOn() ) { |
577 | KMessageBox::sorry( this, |
578 | i18n( "You cannot deactivate the standard resource. " |
579 | "Choose another standard resource first." ) ); |
580 | configItem->setCheckState( 0, Qt::Checked ); |
581 | return; |
582 | } |
583 | |
584 | if ( configItem->isOn() != configItem->resource()->isActive() ) { |
585 | emit changed( true ); |
586 | } |
587 | } |
588 | |
589 | void ConfigPage::Private::saveResourceSettings( ConfigPage *page ) |
590 | { |
591 | if ( mCurrentManager ) { |
592 | for ( int i = 0; i < mListView->topLevelItemCount(); ++i ) { |
593 | ConfigViewItem *configItem = static_cast<ConfigViewItem *>( mListView->topLevelItem( i ) ); |
594 | // check if standard resource |
595 | if ( configItem->standard() && !configItem->readOnly() && |
596 | configItem->isOn() ) { |
597 | mCurrentManager->setStandardResource( configItem->resource() ); |
598 | } |
599 | |
600 | // check if active or passive resource |
601 | configItem->resource()->setActive( configItem->isOn() ); |
602 | } |
603 | mCurrentManager->writeConfig( mCurrentConfig ); |
604 | |
605 | if ( !mCurrentManager->standardResource() ) { |
606 | KMessageBox::sorry( page, |
607 | i18n( "There is no valid standard resource. " |
608 | "Please select one which is neither read-only nor inactive." ) ); |
609 | } |
610 | } |
611 | } |
612 | |
613 | } |
614 | |
615 | |
616 | |