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
59namespace KRES {
60
61class ResourcePageInfo::Private
62{
63};
64
65ResourcePageInfo::ResourcePageInfo() : d( new KRES::ResourcePageInfo::Private )
66{
67 mManager = 0;
68 mConfig = 0;
69}
70
71ResourcePageInfo::~ResourcePageInfo()
72{
73 //delete mManager;
74 mManager = 0;
75 //delete mConfig;
76 mConfig = 0;
77 delete d;
78}
79
80class 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
118class 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
141ConfigPage::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 headerLabels;
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
209ConfigPage::~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
223void 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
278void 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
293void 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
305void ConfigPage::defaults()
306{
307}
308
309void 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
355void 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
415void 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
447void 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
477void 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
511void 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
520void 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
533void 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
546void 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
558ConfigViewItem *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
569void 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
589void 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