00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "ksettings/dialog.h"
00021
00022
00023 #include <kcmultidialog.h>
00024 #include <klocale.h>
00025 #include <kservicegroup.h>
00026 #include <kdebug.h>
00027 #include <ktrader.h>
00028 #include <kplugininfo.h>
00029 #include "ksettings/dispatcher.h"
00030 #include "ksettings/componentsdialog.h"
00031 #include <ksimpleconfig.h>
00032 #include <kstandarddirs.h>
00033 #include <kiconloader.h>
00034 #include <qvbox.h>
00035 #include <qlabel.h>
00036 #include "kcmoduleinfo.h"
00037
00038 namespace KSettings
00039 {
00040
00041 struct GroupInfo
00042 {
00043 QString id;
00044 QString name;
00045 QString comment;
00046 QString icon;
00047 int weight;
00048 QString parentid;
00049 QWidget * page;
00050 };
00051
00052
00053
00054 class PageNode
00055 {
00056 private:
00057 typedef QValueList<PageNode*> List;
00058 enum Type { KCM, Group, Root };
00059 union Value
00060 {
00061 KCModuleInfo * kcm;
00062 GroupInfo * group;
00063 };
00064 Type m_type;
00065 Value m_value;
00066
00067 Dialog * m_dialog;
00068 List m_children;
00069 PageNode * m_parent;
00070 bool m_visible;
00071 bool m_dirty;
00072
00073 protected:
00074 PageNode( KCModuleInfo * info, PageNode * parent )
00075 : m_type( KCM )
00076 , m_parent( parent )
00077 , m_visible( true )
00078 , m_dirty( true )
00079 {
00080 m_value.kcm = info;
00081 m_dialog = parent->m_dialog;
00082 }
00083
00084 PageNode( GroupInfo & group, PageNode * parent )
00085 : m_type( Group )
00086 , m_parent( parent )
00087 , m_visible( true )
00088 , m_dirty( true )
00089 {
00090 m_value.group = new GroupInfo( group );
00091 m_value.group->page = 0;
00092 m_dialog = parent->m_dialog;
00093 }
00094
00095 void bubbleSort( List::Iterator begin, List::Iterator end )
00096 {
00097 --end;
00098 bool finished;
00099 List::Iterator lastswapped = begin;
00100 List::Iterator i;
00101 List::Iterator j;
00102 while( begin != end )
00103 {
00104 finished = true;
00105 i = j = end;
00106 do {
00107 --j;
00108 if( **i < **j )
00109 {
00110 finished = false;
00111 qSwap( *i, *j );
00112 lastswapped = j;
00113 }
00114 --i;
00115 } while( j != begin );
00116 if( finished )
00117 return;
00118 ++lastswapped;
00119 begin = lastswapped;
00120 }
00121 }
00122
00123 public:
00124 PageNode( Dialog * dialog )
00125 : m_type( Root )
00126 , m_dialog( dialog )
00127 , m_parent( 0 )
00128 , m_visible( true )
00129 , m_dirty( true )
00130 {}
00131
00132 ~PageNode()
00133 {
00134 if( KCM == m_type )
00135 delete m_value.kcm;
00136 else if( Group == m_type )
00137 delete m_value.group;
00138 List::Iterator end = m_children.end();
00139 for( List::Iterator it = m_children.begin(); it != end; ++it )
00140 delete ( *it );
00141 }
00142
00143 int weight() const
00144 {
00145 int w = ( KCM == m_type ) ? m_value.kcm->weight()
00146 : m_value.group->weight;
00147 kdDebug( 700 ) << k_funcinfo << name() << " " << w << endl;
00148 return w;
00149 }
00150
00151 bool operator<( const PageNode & rhs ) const
00152 {
00153 return weight() < rhs.weight();
00154 }
00155
00156 bool isVisible()
00157 {
00158 if( m_dirty )
00159 {
00160 if( KCM == m_type )
00161 m_visible = m_dialog->isPluginForKCMEnabled( m_value.kcm );
00162 else
00163 {
00164 m_visible = false;
00165 List::Iterator end = m_children.end();
00166 for( List::Iterator it = m_children.begin(); it != end;
00167 ++it )
00168 if( ( *it )->isVisible() )
00169 {
00170 m_visible = true;
00171 break;
00172 }
00173 }
00174 m_dirty = false;
00175 }
00176 kdDebug( 700 ) << k_funcinfo << "returns " << m_visible << endl;
00177 return m_visible;
00178 }
00179
00180 void makeDirty()
00181 {
00182 m_dirty = true;
00183 List::Iterator end = m_children.end();
00184 for( List::Iterator it = m_children.begin(); it != end; ++it )
00185 ( *it )->makeDirty();
00186 }
00187
00188 QString name() const
00189 {
00190 if( Root == m_type )
00191 return QString::fromAscii( "root node" );
00192 return ( KCM == m_type ) ? m_value.kcm->moduleName()
00193 : m_value.group->name;
00194 }
00195
00196 QStringList parentNames() const
00197 {
00198 QStringList ret;
00199 PageNode * node = m_parent;
00200 while( node && node->m_type != Root )
00201 {
00202 ret.prepend( node->name() );
00203 node = node->m_parent;
00204 }
00205 return ret;
00206 }
00207
00208 void addToDialog( KCMultiDialog * dlg )
00209 {
00210 kdDebug( 700 ) << k_funcinfo << "for " << name() << endl;
00211 if( ! isVisible() )
00212 return;
00213
00214 if( KCM == m_type )
00215 {
00216 dlg->addModule( *m_value.kcm, parentNames() );
00217 return;
00218 }
00219 if( Group == m_type && 0 == m_value.group->page )
00220 {
00221 QPixmap icon;
00222 if( ! m_value.group->icon.isNull() )
00223 icon = SmallIcon( m_value.group->icon,
00224 IconSize( KIcon::Small ) );
00225 QVBox * page = dlg->addVBoxPage( m_value.group->name,
00226 QString::null, icon );
00227 QLabel * comment = new QLabel( m_value.group->comment, page );
00228 comment->setTextFormat( Qt::RichText );
00229 m_value.group->page = page;
00230 }
00231 List::Iterator end = m_children.end();
00232 for( List::Iterator it = m_children.begin(); it != end; ++it )
00233 ( *it )->addToDialog( dlg );
00234 }
00235
00236 void removeFromDialog( KCMultiDialog * dlg )
00237 {
00238 kdDebug( 700 ) << k_funcinfo << "for " << name() << endl;
00239 if( KCM == m_type )
00240 return;
00241 if( Root == m_type )
00242 dlg->removeAllModules();
00243 List::Iterator end = m_children.end();
00244 for( List::Iterator it = m_children.begin(); it != end; ++it )
00245 ( *it )->removeFromDialog( dlg );
00246 if( Group == m_type )
00247 {
00248 delete m_value.group->page;
00249 m_value.group->page = 0;
00250 }
00251 }
00252
00253 void sort()
00254 {
00255 kdDebug( 700 ) << k_funcinfo << name() << endl;
00256 List::Iterator begin = m_children.begin();
00257 List::Iterator end = m_children.end();
00258 bubbleSort( begin, end );
00259 for( List::Iterator it = begin ; it != end; ++it )
00260 ( *it )->sort();
00261 }
00262
00263 bool insert( GroupInfo & group )
00264 {
00265 if( group.parentid.isNull() )
00266 {
00267 if( Root == m_type )
00268 {
00269 m_children.append( new PageNode( group, this ) );
00270 return true;
00271 }
00272 else
00273 kdFatal( 700 ) << "wrong PageNode insertion"
00274 << kdBacktrace() << endl;
00275 }
00276 if( Group == m_type && group.parentid == m_value.group->id )
00277 {
00278 m_children.append( new PageNode( group, this ) );
00279 return true;
00280 }
00281 List::Iterator end = m_children.end();
00282 for( List::Iterator it = m_children.begin(); it != end; ++it )
00283 if( ( *it )->insert( group ) )
00284 return true;
00285
00286 if( Root == m_type )
00287 {
00288 m_children.append( new PageNode( group, this ) );
00289 return true;
00290 }
00291 return false;
00292 }
00293
00294 bool insert( KCModuleInfo * info, const QString & parentid )
00295 {
00296 if( parentid.isNull() )
00297 {
00298 if( Root == m_type )
00299 {
00300 m_children.append( new PageNode( info, this ) );
00301 return true;
00302 }
00303 else
00304 kdFatal( 700 ) << "wrong PageNode insertion"
00305 << kdBacktrace() << endl;
00306 }
00307 if( Group == m_type && parentid == m_value.group->id )
00308 {
00309 m_children.append( new PageNode( info, this ) );
00310 return true;
00311 }
00312 List::Iterator end = m_children.end();
00313 for( List::Iterator it = m_children.begin(); it != end; ++it )
00314 if( ( *it )->insert( info, parentid ) )
00315 return true;
00316
00317 if( Root == m_type )
00318 {
00319 m_children.append( new PageNode( info, this ) );
00320 return true;
00321 }
00322 return false;
00323 }
00324
00325 bool needTree()
00326 {
00327 List::ConstIterator end = m_children.end();
00328 for( List::ConstIterator it = m_children.begin(); it != end; ++it )
00329 if( ( *it )->m_children.count() > 0 )
00330 return true;
00331 return false;
00332 }
00333
00334 bool singleChild()
00335 {
00336 return ( m_children.count() == 1 );
00337 }
00338 };
00339
00340 class Dialog::DialogPrivate
00341 {
00342 public:
00343 DialogPrivate( Dialog * parent )
00344 : dlg( 0 )
00345 , pagetree( parent )
00346 {
00347 }
00348
00349 bool staticlistview;
00350 KCMultiDialog * dlg;
00351 PageNode pagetree;
00352 QWidget * parentwidget;
00353 QStringList registeredComponents;
00354 QValueList<KService::Ptr> services;
00355 QMap<QString, KPluginInfo*> plugininfomap;
00356 };
00357
00358 Dialog::Dialog( QWidget * parent, const char * name )
00359 : QObject( parent, name )
00360 , d( new DialogPrivate( this ) )
00361 {
00362 d->parentwidget = parent;
00363 d->staticlistview = true;
00364 d->services = instanceServices();
00365 }
00366
00367 Dialog::Dialog( ContentInListView content,
00368 QWidget * parent, const char * name )
00369 : QObject( parent, name )
00370 , d( new DialogPrivate( this ) )
00371 {
00372 d->parentwidget = parent;
00373 d->staticlistview = ( content == Static );
00374 d->services = instanceServices();
00375 }
00376
00377 Dialog::Dialog( const QStringList & components,
00378 QWidget * parent, const char * name )
00379 : QObject( parent, name )
00380 , d( new DialogPrivate( this ) )
00381 {
00382 d->parentwidget = parent;
00383 d->staticlistview = true;
00384 d->services = instanceServices() + parentComponentsServices( components );
00385 }
00386
00387 Dialog::Dialog( const QStringList & components,
00388 ContentInListView content, QWidget * parent, const char * name )
00389 : QObject( parent, name )
00390 , d( new DialogPrivate( this ) )
00391 {
00392 d->parentwidget = parent;
00393 d->staticlistview = ( content == Static );
00394 d->services = instanceServices() + parentComponentsServices( components );
00395 }
00396
00397 Dialog::~Dialog()
00398 {
00399 delete d;
00400 }
00401
00402 void Dialog::addPluginInfos( const QValueList<KPluginInfo*> & plugininfos )
00403 {
00404 for( QValueList<KPluginInfo*>::ConstIterator it = plugininfos.begin();
00405 it != plugininfos.end(); ++it )
00406 {
00407 d->registeredComponents.append( ( *it )->pluginName() );
00408 d->services += ( *it )->kcmServices();
00409 d->plugininfomap[ ( *it )->pluginName() ] = *it;
00410 }
00411 }
00412
00413 void Dialog::show()
00414 {
00415 if( 0 == d->dlg )
00416 createDialogFromServices();
00417 Dispatcher::self()->syncConfiguration();
00418 return d->dlg->show();
00419 }
00420
00421 KCMultiDialog * Dialog::dialog()
00422 {
00423 if( 0 == d->dlg )
00424 createDialogFromServices();
00425 return d->dlg;
00426 }
00427
00428 QValueList<KService::Ptr> Dialog::instanceServices() const
00429 {
00430 kdDebug( 700 ) << k_funcinfo << endl;
00431 QString instanceName = KGlobal::instance()->instanceName();
00432 d->registeredComponents.append( instanceName );
00433 kdDebug( 700 ) << "calling KServiceGroup::childGroup( " << instanceName
00434 << " )" << endl;
00435 KServiceGroup::Ptr service = KServiceGroup::childGroup( instanceName );
00436
00437 QValueList<KService::Ptr> ret;
00438
00439 if( service && service->isValid() )
00440 {
00441 kdDebug( 700 ) << "call was successfull" << endl;
00442 KServiceGroup::List list = service->entries();
00443 for( KServiceGroup::List::ConstIterator it = list.begin();
00444 it != list.end(); ++it )
00445 {
00446 KSycocaEntry * p = *it;
00447 if( p->isType( KST_KService ) )
00448 {
00449 kdDebug( 700 ) << "found service" << endl;
00450 ret << static_cast<KService *>( p );
00451 }
00452 else
00453 kdWarning( 700 ) << "KServiceGroup::childGroup returned"
00454 " something else than a KService (kinda)" << endl;
00455 }
00456 }
00457
00458 return ret;
00459 }
00460
00461 QValueList<KService::Ptr> Dialog::parentComponentsServices(
00462 const QStringList & kcdparents ) const
00463 {
00464 d->registeredComponents += kcdparents;
00465 QString constraint = kcdparents.join(
00466 "' in [X-KDE-ParentComponents]) or ('" );
00467 constraint = "('" + constraint + "' in [X-KDE-ParentComponents])";
00468
00469 kdDebug( 700 ) << "constraint = " << constraint << endl;
00470 return KTrader::self()->query( "KCModule", constraint );
00471 }
00472
00473 bool Dialog::isPluginForKCMEnabled( KCModuleInfo * moduleinfo ) const
00474 {
00475
00476
00477 bool enabled = true;
00478 kdDebug( 700 ) << "check whether the " << moduleinfo->moduleName()
00479 << " KCM should be shown" << endl;
00480
00481 QStringList parentComponents = moduleinfo->service()->property(
00482 "X-KDE-ParentComponents" ).toStringList();
00483 for( QStringList::ConstIterator pcit = parentComponents.begin();
00484 pcit != parentComponents.end(); ++pcit )
00485 {
00486
00487 if( d->registeredComponents.find( *pcit ) ==
00488 d->registeredComponents.end() )
00489 continue;
00490
00491
00492 if( ! d->plugininfomap.contains( *pcit ) )
00493 {
00494
00495 enabled = true;
00496
00497 break;
00498 }
00499
00500 KPluginInfo * pinfo = d->plugininfomap[ *pcit ];
00501 pinfo->load();
00502 enabled = pinfo->isPluginEnabled();
00503 kdDebug( 700 ) << "parent " << *pcit << " is "
00504 << ( enabled ? "enabled" : "disabled" ) << endl;
00505
00506 if( enabled )
00507 break;
00508 }
00509 return enabled;
00510 }
00511
00512 void Dialog::parseGroupFile( const QString & filename )
00513 {
00514 KSimpleConfig file( filename );
00515 QStringList groups = file.groupList();
00516 for( QStringList::ConstIterator it = groups.begin(); it != groups.end();
00517 ++it )
00518 {
00519 GroupInfo group;
00520 QString id = *it;
00521 file.setGroup( id.utf8() );
00522 group.id = id;
00523 group.name = file.readEntry( "Name" );
00524 group.comment = file.readEntry( "Comment" );
00525 group.weight = file.readNumEntry( "Weight", 100 );
00526 group.parentid = file.readEntry( "Parent" );
00527 group.icon = file.readEntry( "Icon" );
00528 d->pagetree.insert( group );
00529 }
00530 }
00531
00532 void Dialog::createDialogFromServices()
00533 {
00534
00535 QString setdlgpath = locate( "appdata",
00536 KGlobal::instance()->instanceName() + ".setdlg" );
00537 QStringList setdlgaddon = KGlobal::dirs()->findAllResources( "appdata",
00538 "ksettingsdialog/*.setdlg" );
00539 if( ! setdlgpath.isNull() )
00540 parseGroupFile( setdlgpath );
00541 if( setdlgaddon.size() > 0 )
00542 for( QStringList::ConstIterator it = setdlgaddon.begin();
00543 it != setdlgaddon.end(); ++it )
00544 parseGroupFile( *it );
00545
00546
00547 for( QValueList<KService::Ptr>::ConstIterator it = d->services.begin();
00548 it != d->services.end(); ++it )
00549 {
00550
00551 KCModuleInfo * info = new KCModuleInfo( *it );
00552 QString parentid;
00553 QVariant tmp = info->service()->property( "X-KDE-CfgDlgHierarchy",
00554 QVariant::String );
00555 if( tmp.isValid() )
00556 parentid = tmp.toString();
00557 d->pagetree.insert( info, parentid );
00558 }
00559
00560
00561
00562 d->pagetree.sort();
00563
00564 int dialogface = KJanusWidget::IconList;
00565 if( d->pagetree.needTree() )
00566 dialogface = KJanusWidget::TreeList;
00567 else if( d->pagetree.singleChild() )
00568 dialogface = KJanusWidget::Plain;
00569
00570 kdDebug( 700 ) << "creating KCMultiDialog" << endl;
00571 d->dlg = new KCMultiDialog( dialogface, i18n( "Configure" ),
00572 d->parentwidget );
00573
00574 if( dialogface == KJanusWidget::TreeList )
00575 d->dlg->setShowIconsInTreeList( true );
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589 if( ! d->staticlistview )
00590 d->dlg->addButtonBelowList( i18n( "Select Components..." ), this,
00591 SLOT( configureTree() ) );
00592
00593 connect( d->dlg, SIGNAL( okClicked() ), Dispatcher::self(),
00594 SLOT( syncConfiguration() ) );
00595 connect( d->dlg, SIGNAL( applyClicked() ), Dispatcher::self(),
00596 SLOT( syncConfiguration() ) );
00597 connect( d->dlg, SIGNAL( configCommitted( const QCString & ) ),
00598 Dispatcher::self(), SLOT( reparseConfiguration( const QCString & ) ) );
00599
00600 d->pagetree.addToDialog( d->dlg );
00601
00602 if( dialogface == KJanusWidget::TreeList )
00603 d->dlg->unfoldTreeList();
00604 }
00605
00606 void Dialog::configureTree()
00607 {
00608 kdDebug( 700 ) << k_funcinfo << endl;
00609 ComponentsDialog * subdlg = new ComponentsDialog( d->dlg );
00610 subdlg->setPluginInfos( d->plugininfomap );
00611 subdlg->show();
00612 connect( subdlg, SIGNAL( okClicked() ), this, SLOT( updateTreeList() ) );
00613 connect( subdlg, SIGNAL( applyClicked() ), this, SLOT( updateTreeList() ) );
00614 connect( subdlg, SIGNAL( okClicked() ), this,
00615 SIGNAL( pluginSelectionChanged() ) );
00616 connect( subdlg, SIGNAL( applyClicked() ), this,
00617 SIGNAL( pluginSelectionChanged() ) );
00618 connect( subdlg, SIGNAL( finished() ), subdlg, SLOT( delayedDestruct() ) );
00619 }
00620
00621 void Dialog::updateTreeList()
00622 {
00623 kdDebug( 700 ) << k_funcinfo << endl;
00624
00625 d->pagetree.makeDirty();
00626
00627
00628
00629
00630
00631 d->pagetree.removeFromDialog( d->dlg );
00632 d->pagetree.addToDialog( d->dlg );
00633
00634 if( d->pagetree.needTree() )
00635 d->dlg->unfoldTreeList( true );
00636 }
00637
00638 }
00639
00640 #include "dialog.moc"
00641
00642