kcmultidialog.cpp

00001 /*
00002    Copyright (c) 2000 Matthias Elter <elter@kde.org>
00003    Copyright (c) 2003 Daniel Molkentin <molkentin@kde.org>
00004    Copyright (c) 2003 Matthias Kretz <kretz@kde.org>
00005    Copyright (c) 2004 Frans Englich <frans.erglich.com>
00006 
00007    This library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Library General Public
00009    License as published by the Free Software Foundation; either
00010    version 2 of the License, or (at your option) any later version.
00011 
00012    This library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Library General Public License for more details.
00016 
00017    You should have received a copy of the GNU Library General Public License
00018    along with this library; see the file COPYING.LIB.  If not, write to
00019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020    Boston, MA 02110-1301, USA.
00021 
00022 */
00023 
00024 #include <qcursor.h>
00025 #include <qhbox.h>
00026 #include <qlayout.h>
00027 #include <qpushbutton.h>
00028 
00029 #include <kaboutdata.h>
00030 #include <kapplication.h>
00031 #include <kdebug.h>
00032 #include <kiconloader.h>
00033 #include <klibloader.h>
00034 #include <klocale.h>
00035 #include <kmessagebox.h>
00036 #include <kprocess.h>
00037 #include <krun.h>
00038 #include <kstdguiitem.h>
00039 #include <kuser.h>
00040 
00041 #include "kcmoduleloader.h"
00042 #include "kcmoduleproxy.h"
00043 #include "kcmultidialog.h"
00044 #include "kcmultidialog.moc"
00045 
00046 class KCMultiDialog::KCMultiDialogPrivate
00047 {
00048     public:
00049         KCMultiDialogPrivate()
00050             : hasRootKCM( false ), currentModule( 0 )
00051         {}
00052 
00053         bool hasRootKCM;
00054         KCModuleProxy* currentModule;
00055 };
00056 
00057  
00058 KCMultiDialog::KCMultiDialog(QWidget *parent, const char *name, bool modal)
00059     : KDialogBase(IconList, i18n("Configure"), Help | Default |Cancel | Apply |
00060             Ok | User1 | User2, Ok, parent, name, modal, true,
00061             KStdGuiItem::reset(), KStdGuiItem::adminMode())
00062     , dialogface( IconList ), d( new KCMultiDialogPrivate )
00063 {
00064     init();
00065 }
00066 
00067 KCMultiDialog::KCMultiDialog( int dialogFace, const QString & caption, QWidget * parent, const char * name, bool modal )
00068     : KDialogBase( dialogFace, caption, Help | Default | Cancel | Apply | Ok |
00069             User1 | User2, Ok, parent, name, modal, true,
00070             KStdGuiItem::reset(), KStdGuiItem::adminMode())
00071     , dialogface( dialogFace ), d( new KCMultiDialogPrivate )
00072 {
00073     init();
00074 }
00075 
00076 KCMultiDialog::KCMultiDialog( int dialogFace, const KGuiItem &user2,
00077         const KGuiItem &user3, int buttonMask, const QString &caption,
00078         QWidget *parent, const char *name, bool modal )
00079     : KDialogBase( dialogFace, caption, buttonMask | Help | Default | Cancel |
00080             Apply | Ok | User1, Ok, parent, name, modal, true,
00081             KStdGuiItem::reset(), user2, user3 )
00082     , dialogface( dialogFace ), d( new KCMultiDialogPrivate )
00083 {
00084     kdDebug( 710 ) << "Root modules will not work with this constructor. See the API documentation." << endl;
00085     init();
00086     if ( buttonMask & User2 )
00087         showButton( User2, true );
00088 }
00089 
00090 inline void KCMultiDialog::init()
00091 {
00092     connect( this, SIGNAL( finished()), SLOT( dialogClosed()));
00093     showButton( User1, false );
00094     showButton( User2, false );
00095     enableButton(Apply, false);
00096     connect(this, SIGNAL(aboutToShowPage(QWidget *)), this, SLOT(slotAboutToShow(QWidget *)));
00097     setInitialSize(QSize(640,480));
00098     moduleParentComponents.setAutoDelete( true );
00099 
00100 }
00101 
00102 KCMultiDialog::~KCMultiDialog()
00103 {
00104     OrphanMap::Iterator end2 = m_orphanModules.end();
00105     for( OrphanMap::Iterator it = m_orphanModules.begin(); it != end2; ++it )
00106         delete ( *it );
00107 }
00108 
00109 void KCMultiDialog::slotDefault()
00110 {
00111     int curPageIndex = activePageIndex();
00112 
00113     ModuleList::Iterator end = m_modules.end();
00114     for( ModuleList::Iterator it = m_modules.begin(); it != end; ++it )
00115         if( pageIndex( ( QWidget * )( *it ).kcm->parent() ) == curPageIndex )
00116         {
00117           ( *it ).kcm->defaults();
00118           clientChanged( true );
00119           return;
00120         }
00121 }
00122 
00123 void KCMultiDialog::slotUser1()
00124 {
00125     int curPageIndex = activePageIndex();
00126 
00127     ModuleList::Iterator end = m_modules.end();
00128     for( ModuleList::Iterator it = m_modules.begin(); it != end; ++it )
00129         if( pageIndex( ( QWidget * )( *it ).kcm->parent() ) == curPageIndex )
00130         {
00131             ( *it ).kcm->load();
00132             clientChanged( false );
00133             return;
00134         }
00135 }
00136 
00137 void KCMultiDialog::apply()
00138 {
00139     QStringList updatedModules;
00140     ModuleList::Iterator end = m_modules.end();
00141     for( ModuleList::Iterator it = m_modules.begin(); it != end; ++it )
00142     {
00143         KCModuleProxy * m = ( *it ).kcm;
00144         if( m->changed() )
00145         {
00146             m->save();
00147             QStringList * names = moduleParentComponents[ m ];
00148             kdDebug(710) << k_funcinfo << *names << " saved and added to the list" << endl;
00149             for( QStringList::ConstIterator it = names->begin(); it != names->end(); ++it )
00150                 if( updatedModules.find( *it ) == updatedModules.end() )
00151                     updatedModules.append( *it );
00152         }
00153     }
00154     for( QStringList::const_iterator it = updatedModules.begin(); it != updatedModules.end(); ++it )
00155     {
00156         kdDebug(710) << k_funcinfo << *it << " " << ( *it ).latin1() << endl;
00157         emit configCommitted( ( *it ).latin1() );
00158     }
00159     emit configCommitted();
00160 }
00161 
00162 void KCMultiDialog::slotApply()
00163 {
00164     QPushButton *button = actionButton(Apply);
00165     if (button)
00166         button->setFocus();
00167     emit applyClicked();
00168     apply();
00169 }
00170 
00171 
00172 void KCMultiDialog::slotOk()
00173 {
00174     QPushButton *button = actionButton(Ok);
00175     if (button)
00176         button->setFocus();
00177     emit okClicked();
00178     apply();
00179     accept();
00180 }
00181 
00182 void KCMultiDialog::slotHelp()
00183 {
00184     QString docPath;
00185 
00186     int curPageIndex = activePageIndex();
00187     ModuleList::Iterator end = m_modules.end();
00188     for( ModuleList::Iterator it = m_modules.begin(); it != end; ++it )
00189         if( pageIndex( ( QWidget * )( *it ).kcm->parent() ) == curPageIndex )
00190         {
00191             docPath = ( *it ).kcm->moduleInfo().docPath();
00192             break;
00193         }
00194 
00195     KURL url( KURL("help:/"), docPath );
00196 
00197     if (url.protocol() == "help" || url.protocol() == "man" || url.protocol() == "info") {
00198         KProcess process;
00199         process << "khelpcenter"
00200                 << url.url();
00201         process.start(KProcess::DontCare);
00202         process.detach();
00203     } else {
00204         new KRun(url);
00205     }
00206 }
00207 
00208 void KCMultiDialog::clientChanged(bool state)
00209 {
00210     kdDebug( 710 ) << k_funcinfo << state << endl;
00211     ModuleList::Iterator end = m_modules.end();
00212     for( ModuleList::Iterator it = m_modules.begin(); it != end; ++it )
00213         if( ( *it ).kcm->changed() )
00214         {
00215             enableButton( Apply, true );
00216             return;
00217         }
00218     enableButton( Apply, false );
00219 }
00220 
00221 void KCMultiDialog::addModule(const QString& path, bool withfallback)
00222 {
00223     QString complete = path;
00224 
00225     if( !path.endsWith( ".desktop" ))
00226         complete += ".desktop";
00227 
00228     KService::Ptr service = KService::serviceByStorageId( complete );
00229 
00230     addModule( KCModuleInfo( service ), QStringList(), withfallback);
00231 }
00232 
00233 void KCMultiDialog::addModule(const KCModuleInfo& moduleinfo,
00234         QStringList parentmodulenames, bool withfallback)
00235 {
00236     kdDebug(710) << "KCMultiDialog::addModule " 
00237         << moduleinfo.moduleName() << endl;
00238 
00239     if( !moduleinfo.service() )
00240         return;
00241 
00242     if ( !kapp->authorizeControlModule( moduleinfo.service()->menuId() ))
00243             return;
00244 
00245     if( !KCModuleLoader::testModule( moduleinfo ))
00246             return;
00247 
00248     QFrame* page = 0;
00249     if (!moduleinfo.service()->noDisplay())
00250         switch( dialogface )
00251         {
00252             case TreeList:
00253                 parentmodulenames += moduleinfo.moduleName();
00254                 page = addHBoxPage( parentmodulenames, moduleinfo.comment(),
00255                         SmallIcon( moduleinfo.icon(),
00256                             IconSize( KIcon::Small ) ) );
00257                 break;
00258             case IconList:
00259                 page = addHBoxPage( moduleinfo.moduleName(),
00260                         moduleinfo.comment(), DesktopIcon( moduleinfo.icon(),
00261                             KIcon::SizeMedium ) );
00262                 break;
00263             case Plain:
00264                 page = plainPage();
00265                 ( new QHBoxLayout( page ) )->setAutoAdd( true );
00266                 break;
00267             default:
00268                 kdError( 710 ) << "unsupported dialog face for KCMultiDialog"
00269                     << endl;
00270                 break;
00271         }
00272     if(!page) {
00273         KCModuleLoader::unloadModule(moduleinfo);
00274         return;
00275     }
00276     KCModuleProxy * module;
00277     if( m_orphanModules.contains( moduleinfo.service() ) )
00278     {
00279         // the KCModule already exists - it was removed from the dialog in
00280         // removeAllModules
00281         module = m_orphanModules[ moduleinfo.service() ];
00282         m_orphanModules.remove( moduleinfo.service() );
00283         kdDebug( 710 ) << "Use KCModule from the list of orphans for " <<
00284             moduleinfo.moduleName() << ": " << module << endl;
00285 
00286         module->reparent( page, 0, QPoint( 0, 0 ), true );
00287 
00288         if( module->changed() )
00289             clientChanged( true );
00290 
00291         if( activePageIndex() == -1 )
00292             showPage( pageIndex( page ) );
00293     }
00294     else
00295     {
00296         module = new KCModuleProxy( moduleinfo, withfallback, page );
00297         QStringList parentComponents = moduleinfo.service()->property(
00298                 "X-KDE-ParentComponents" ).toStringList();
00299         moduleParentComponents.insert( module,
00300                 new QStringList( parentComponents ) );
00301 
00302         connect(module, SIGNAL(changed(bool)), this, SLOT(clientChanged(bool)));
00303 
00304         if( m_modules.count() == 0 )
00305             aboutToShowPage( page );
00306     }
00307     CreatedModule cm;
00308     cm.kcm = module;
00309     cm.service = moduleinfo.service();
00310     m_modules.append( cm );
00311     if ( moduleinfo.needsRootPrivileges() && 
00312             !d->hasRootKCM &&
00313             !KUser().isSuperUser() ) /* If we're embedded, it's true */
00314     {
00315         d->hasRootKCM = true;
00316         showButton( User2, true );
00317         if( plainPage() ) // returns 0 if we're not a Plain dialog
00318             slotAboutToShow( page ); // Won't be called otherwise, necessary for adminMode button
00319     }
00320 }
00321 
00322 void KCMultiDialog::removeAllModules()
00323 {
00324     kdDebug( 710 ) << k_funcinfo << endl;
00325     ModuleList::Iterator end = m_modules.end();
00326     for( ModuleList::Iterator it = m_modules.begin(); it != end; ++it )
00327     {
00328         kdDebug( 710 ) << "remove 2" << endl;
00329         KCModuleProxy * kcm = ( *it ).kcm;
00330         QObject * page = kcm->parent();
00331         kcm->hide();
00332         if( page )
00333         {
00334             // I hate this
00335             kcm->reparent( 0, QPoint( 0, 0 ), false );
00336             delete page;
00337         }
00338         m_orphanModules[ ( *it ).service ] = kcm;
00339         kdDebug( 710 ) << "added KCModule to the list of orphans: " <<
00340             kcm << endl;
00341     }
00342     m_modules.clear();
00343     // all modules are gone, none can be changed
00344     clientChanged( false );
00345 }
00346 
00347 void KCMultiDialog::show()
00348 { /* KDE 4 Remove..? */
00349     KDialogBase::show();
00350 }
00351 
00352 void KCMultiDialog::slotAboutToShow(QWidget *page)
00353 {
00354     kdDebug(710) << k_funcinfo << endl;
00355 
00356     QObject * obj = page->child( 0, "KCModuleProxy" );
00357     if( ! obj )
00358         return;
00359 
00360     KCModuleProxy * module = ( KCModuleProxy* )obj->qt_cast(
00361             "KCModuleProxy" );
00362     if( ! module )
00363         return;
00364     d->currentModule = module;
00365 
00366     enableButton( KDialogBase::Help,
00367             d->currentModule->buttons() & KCModule::Help );
00368     enableButton( KDialogBase::Default,
00369             d->currentModule->buttons() & KCModule::Default );
00370 
00371     disconnect( this, SIGNAL(user2Clicked()), 0, 0 );
00372 
00373     if (d->currentModule->moduleInfo().needsRootPrivileges())
00374     {
00375         if ( !d->currentModule->rootMode() )
00376             { /* Enable the Admin Mode button */
00377             enableButton( User2, true );
00378             connect( this, SIGNAL(user2Clicked()), d->currentModule, SLOT( runAsRoot() ));
00379             connect( this, SIGNAL(user2Clicked()), SLOT( disableRModeButton() ));
00380         }
00381         else
00382             enableButton( User2, false);
00383     }
00384 }
00385 
00386 void KCMultiDialog::rootExit()
00387 {
00388     enableButton( User2, true);
00389 }
00390 
00391 void KCMultiDialog::disableRModeButton()
00392 {
00393     enableButton( User2, false );
00394     connect ( d->currentModule, SIGNAL( childClosed() ), SLOT( rootExit() ));
00395 }
00396 
00397 void KCMultiDialog::dialogClosed()
00398 {
00399     kdDebug(710) << k_funcinfo << endl;
00400 
00401     /* If we don't delete them, the DCOP registration stays, and trying to load the KCMs 
00402      * in other situations will lead to "module already loaded in Foo," while to the user 
00403      * doesn't appear so(the dialog is hidden) */
00404     ModuleList::Iterator end = m_modules.end();
00405     for( ModuleList::Iterator it = m_modules.begin(); it != end; ++it )
00406             ( *it ).kcm->deleteClient();
00407 }
00408 
00409 
00410 // vim: sw=4 et sts=4
KDE Home | KDE Accessibility Home | Description of Access Keys