kutils Library API Documentation

dialog.cpp

00001 /* This file is part of the KDE project 00002 Copyright (C) 2003 Matthias Kretz <kretz@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License version 2 as published by the Free Software Foundation. 00007 00008 This library is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 Library General Public License for more details. 00012 00013 You should have received a copy of the GNU Library General Public License 00014 along with this library; see the file COPYING.LIB. If not, write to 00015 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00016 Boston, MA 02111-1307, USA. 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 // The TreeList can get really complicated. That's why a tree data structure 00053 // is necessary to make it suck less 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 // no parent with the right parentid 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 // no parent with the right parentid 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 // if the user of this class requested to hide disabled modules 00476 // we check whether it should be enabled or not 00477 bool enabled = true; 00478 kdDebug( 700 ) << "check whether the " << moduleinfo->moduleName() 00479 << " KCM should be shown" << endl; 00480 // for all parent components 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 // if the parentComponent is not registered ignore it 00487 if( d->registeredComponents.find( *pcit ) == 00488 d->registeredComponents.end() ) 00489 continue; 00490 00491 // we check if the parent component is a plugin 00492 if( ! d->plugininfomap.contains( *pcit ) ) 00493 { 00494 // if not the KCModule must be enabled 00495 enabled = true; 00496 // we're done for this KCModuleInfo 00497 break; 00498 } 00499 // if it is a plugin we check whether the plugin is enabled 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 // if it is enabled we're done for this KCModuleInfo 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 // read .setdlg files 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 // now we process the KCModule services 00547 for( QValueList<KService::Ptr>::ConstIterator it = d->services.begin(); 00548 it != d->services.end(); ++it ) 00549 { 00550 // we create the KCModuleInfo 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 // At this point d->pagetree holds a nice structure of the pages we want 00561 // to show. It's not going to change anymore so we can sort it now. 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 // TODO: Don't show the reset button until the issue with the 00578 // KPluginSelector::load() method is solved. 00579 // Problem: 00580 // KCMultiDialog::show() call KCModule::load() to reset all KCMs 00581 // (KPluginSelector::load() resets all plugin selections and all plugin 00582 // KCMs). 00583 // The reset button calls KCModule::load(), too but in this case we want the 00584 // KPluginSelector to only reset the current visible plugin KCM and not 00585 // touch the plugin selections. 00586 // I have no idea how to check that in KPluginSelector::load()... 00587 //d->dlg->showButton( KDialogBase::User1, true ); 00588 00589 if( ! d->staticlistview ) 00590 d->dlg->addButtonBelowList( i18n( "Configure..." ), 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( true ); 00604 } 00605 00606 void Dialog::configureTree() 00607 { 00608 kdDebug( 700 ) << k_funcinfo << endl; 00609 // FIXME mem leak 00610 ComponentsDialog * subdlg = new ComponentsDialog( d->dlg ); 00611 subdlg->setPluginInfos( d->plugininfomap ); 00612 subdlg->show(); 00613 connect( subdlg, SIGNAL( okClicked() ), this, SLOT( updateTreeList() ) ); 00614 connect( subdlg, SIGNAL( applyClicked() ), this, SLOT( updateTreeList() ) ); 00615 connect( subdlg, SIGNAL( okClicked() ), this, 00616 SIGNAL( pluginSelectionChanged() ) ); 00617 connect( subdlg, SIGNAL( applyClicked() ), this, 00618 SIGNAL( pluginSelectionChanged() ) ); 00619 connect( subdlg, SIGNAL( finished() ), subdlg, 00620 SLOT( delayedDestruct() ) ); 00621 } 00622 00623 void Dialog::updateTreeList() 00624 { 00625 kdDebug( 700 ) << k_funcinfo << endl; 00626 00627 d->pagetree.makeDirty(); 00628 00629 // remove all pages from the dialog and then add them again. This is needed 00630 // because KDialogBase/KJanusWidget can only append to the end of the list 00631 // and we need to have a predefined order. 00632 00633 d->pagetree.removeFromDialog( d->dlg ); 00634 d->pagetree.addToDialog( d->dlg ); 00635 00636 if( d->pagetree.needTree() ) 00637 d->dlg->unfoldTreeList( true ); 00638 } 00639 00640 } //namespace 00641 00642 #include "dialog.moc" 00643 00644 // vim: sw=4 ts=4 noet
KDE Logo
This file is part of the documentation for kutils Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 10 18:55:44 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003