• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KUtils

dialog.cpp

Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
00016     Boston, MA 02110-1301, 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( "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     // remove all pages from the dialog and then add them again. This is needed
00628     // because KDialogBase/KJanusWidget can only append to the end of the list
00629     // and we need to have a predefined order.
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 } //namespace
00639 
00640 #include "dialog.moc"
00641 
00642 // vim: sw=4 ts=4 noet

KUtils

Skip menu "KUtils"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal