00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <qapplication.h>
00021 #include <qcursor.h>
00022 #include <qdatastream.h>
00023 #include <qevent.h>
00024 #include <qfileinfo.h>
00025 #include <qframe.h>
00026 #include <qlabel.h>
00027 #include <qlayout.h>
00028 #include <qpoint.h>
00029 #include <qscrollview.h>
00030 #include <qtextstream.h>
00031 #include <qvbox.h>
00032 #include <qwhatsthis.h>
00033 #include <qwidget.h>
00034
00035 #include <dcopclient.h>
00036 #include <qxembed.h>
00037
00038 #include <kapplication.h>
00039 #include <kaboutdata.h>
00040 #include <kcmodule.h>
00041 #include <kcmoduleinfo.h>
00042 #include <kcmoduleloader.h>
00043 #include <kdebug.h>
00044 #include <kdialog.h>
00045 #include <klocale.h>
00046 #include <kprocess.h>
00047 #include <kservice.h>
00048 #include <kstandarddirs.h>
00049 #include <kuser.h>
00050
00051 #include <X11/Xlib.h>
00052
00053 #include "kcmoduleproxy.h"
00054 #include "kcmoduleproxyIface.h"
00055 #include "kcmoduleproxyIfaceImpl.h"
00056
00057
00058 class KCModuleProxy::KCModuleProxyPrivate
00059 {
00060 public:
00061 KCModuleProxyPrivate( const KCModuleInfo & info )
00062 : args( 0 )
00063 , kcm( 0 )
00064
00065 , embedWidget( 0 )
00066 , rootProcess ( 0 )
00067 , embedFrame ( 0 )
00068 , dcopObject( 0 )
00069 , dcopClient( 0 )
00070 , topLayout( 0 )
00071 , rootCommunicator( 0 )
00072 , rootInfo( 0 )
00073 , modInfo( info )
00074 , withFallback( false )
00075 , changed( false )
00076 , rootMode( false )
00077 , bogusOccupier( false )
00078 , isInitialized( false )
00079 {}
00080
00081 ~KCModuleProxyPrivate()
00082 {
00083 delete embedFrame;
00084 delete dcopClient;
00085 delete dcopObject;
00086 delete embedWidget;
00087 delete rootCommunicator;
00088 delete rootProcess;
00089 delete rootInfo;
00090 delete kcm;
00091 }
00092
00093 QStringList args;
00094 KCModule *kcm;
00095 QXEmbed *embedWidget;
00096 KProcess *rootProcess;
00097 QVBox *embedFrame;
00098 KCModuleProxyIfaceImpl *dcopObject;
00099 DCOPClient *dcopClient;
00100 QVBoxLayout *topLayout;
00101 KCModuleProxyRootCommunicatorImpl *rootCommunicator;
00102 QLabel *rootInfo;
00103 QCString dcopName;
00104 KCModuleInfo modInfo;
00105 bool withFallback;
00106 bool changed;
00107 bool rootMode;
00108 bool bogusOccupier;
00109 bool isInitialized;
00110 };
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 KCModule * KCModuleProxy::realModule() const
00141 {
00142
00143
00144
00145
00146
00147
00148 kdDebug(711) << k_funcinfo << endl;
00149
00150
00151 if( d->kcm )
00152 return d->kcm;
00153
00154
00155 if( d->rootMode )
00156 return 0;
00157
00158 QApplication::setOverrideCursor( Qt::WaitCursor );
00159
00160 KCModuleProxy * that = const_cast<KCModuleProxy*>( this );
00161
00162 if( !d->isInitialized )
00163 {
00164 d->dcopName = moduleInfo().handle().prepend("KCModuleProxy-").utf8();
00165 d->topLayout = new QVBoxLayout( that, 0, 0, "topLayout" );
00166
00167 d->isInitialized = true;
00168 }
00169
00170 if( !d->dcopClient )
00171 d->dcopClient = new DCOPClient();
00172
00173 if( !d->dcopClient->isRegistered() )
00174 d->dcopClient->registerAs( d->dcopName, false );
00175
00176 d->dcopClient->setAcceptCalls( true );
00177
00178 if( d->dcopClient->appId() == d->dcopName || d->bogusOccupier )
00179 {
00180
00181 kdDebug(711) << "Module not already loaded, loading module" << endl;
00182
00183 d->dcopObject = new KCModuleProxyIfaceImpl( d->dcopName, that );
00184
00185 d->kcm = KCModuleLoader::loadModule( moduleInfo(), KCModuleLoader::Inline, d->withFallback,
00186 that, name(), d->args );
00187
00188 connect( d->kcm, SIGNAL( changed( bool ) ),
00189 SLOT(moduleChanged(bool)) );
00190 connect( d->kcm, SIGNAL( destroyed() ),
00191 SLOT( moduleDestroyed() ) );
00192 connect( d->kcm, SIGNAL(quickHelpChanged()),
00193 SIGNAL(quickHelpChanged()));
00194 QWhatsThis::add( that, d->kcm->quickHelp() );
00195
00196 d->topLayout->addWidget( d->kcm );
00197
00198 if ( !d->rootInfo &&
00199 moduleInfo().needsRootPrivileges() &&
00200 !KUser().isSuperUser() )
00201 {
00202
00203 d->rootInfo = new QLabel( that, "rootInfo" );
00204 d->topLayout->insertWidget( 0, d->rootInfo );
00205
00206 d->rootInfo->setFrameShape(QFrame::Box);
00207 d->rootInfo->setFrameShadow(QFrame::Raised);
00208
00209 const QString msg = d->kcm->rootOnlyMsg();
00210 if( msg.isEmpty() )
00211 d->rootInfo->setText(i18n(
00212 "<b>Changes in this section requires root access.</b><br />"
00213 "Click the \"Administrator Mode\" button to "
00214 "allow modifications."));
00215 else
00216 d->rootInfo->setText(msg);
00217
00218 QWhatsThis::add( d->rootInfo, i18n(
00219 "This section requires special permissions, probably "
00220 "for system-wide changes; therefore, it is "
00221 "required that you provide the root password to be "
00222 "able to change the module's properties. If "
00223 "you do not provide the password, the module will be "
00224 "disabled."));
00225 }
00226 }
00227 else
00228 {
00229 kdDebug(711) << "Module already loaded, loading KCMError" << endl;
00230
00231 d->dcopClient->detach();
00232
00233 d->dcopClient->attach();
00234
00235 d->dcopClient->setNotifications( true );
00236 connect( d->dcopClient, SIGNAL( applicationRemoved( const QCString& )),
00237 SLOT( applicationRemoved( const QCString& )));
00238
00239
00240 QByteArray replyData, data;
00241 QCString replyType;
00242 QString result;
00243 QDataStream arg, stream( replyData, IO_ReadOnly );
00244
00245 if( d->dcopClient->call( d->dcopName, d->dcopName, "applicationName()",
00246 data, replyType, replyData ))
00247 {
00248 stream >> result;
00249
00250 d->kcm = KCModuleLoader::reportError( KCModuleLoader::Inline,
00251 i18n( "Argument is application name", "This configuration section is "
00252 "already opened in %1" ).arg( result ), " ", that );
00253
00254 d->topLayout->addWidget( d->kcm );
00255 }
00256 else
00257 {
00258 kdDebug(711) << "Calling KCModuleProxy's DCOP interface for fetching the name failed." << endl;
00259 d->bogusOccupier = true;
00260 QApplication::restoreOverrideCursor();
00261 return realModule();
00262 }
00263 }
00264
00265 QApplication::restoreOverrideCursor();
00266
00267 return d->kcm;
00268 }
00269
00270 void KCModuleProxy::applicationRemoved( const QCString& app )
00271 {
00272 if( app == d->dcopName )
00273 {
00274
00275
00276 delete d->kcm;
00277 d->kcm = 0;
00278 d->dcopClient->setNotifications( false );
00279 realModule();
00280 d->kcm->show();
00281 }
00282 }
00283
00284 void KCModuleProxy::showEvent( QShowEvent * ev )
00285 {
00286
00287 kdDebug(711) << k_funcinfo << endl;
00288 ( void )realModule();
00289
00290
00291 if( d->kcm )
00292 d->kcm->show();
00293
00294 QWidget::showEvent( ev );
00295
00296 }
00297
00298 void KCModuleProxy::runAsRoot()
00299 {
00300 if ( !moduleInfo().needsRootPrivileges() )
00301 return;
00302
00303 QApplication::setOverrideCursor( Qt::WaitCursor );
00304
00305 delete d->rootProcess;
00306 delete d->embedWidget;
00307 delete d->embedFrame;
00308
00309 d->embedFrame = new QVBox( this, "embedFrame" );
00310 d->embedFrame->setFrameStyle( QFrame::Box | QFrame::Raised );
00311
00312 QPalette pal( red );
00313 pal.setColor( QColorGroup::Background,
00314 colorGroup().background() );
00315 d->embedFrame->setPalette( pal );
00316 d->embedFrame->setLineWidth( 2 );
00317 d->embedFrame->setMidLineWidth( 2 );
00318 d->topLayout->addWidget(d->embedFrame,1);
00319
00320 d->embedWidget = new QXEmbed( d->embedFrame, "embedWidget" );
00321
00322 d->embedFrame->show();
00323
00324 QLabel *lblBusy = new QLabel(i18n("<big>Loading...</big>"), d->embedWidget, "lblBusy" );
00325 lblBusy->setTextFormat(RichText);
00326 lblBusy->setAlignment(AlignCenter);
00327 lblBusy->setGeometry(0,0, d->kcm->width(), d->kcm->height());
00328 lblBusy->show();
00329
00330 deleteClient();
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343 QString cmd = moduleInfo().service()->exec().stripWhiteSpace();
00344 if (cmd.left(5) == "kdesu")
00345 {
00346 cmd = cmd.remove(0,5).stripWhiteSpace();
00347
00348
00349 while( cmd.length() > 1 && cmd[ 0 ] == '-' )
00350 cmd = cmd.remove( 0, cmd.find( ' ' ) ).stripWhiteSpace();
00351 }
00352
00353 if (cmd.left(8) == "kcmshell")
00354 cmd = cmd.remove(0,8).stripWhiteSpace();
00355
00356
00357 QString kdesu = KStandardDirs::findExe("kdesu");
00358 if (!kdesu.isEmpty())
00359 {
00360
00361 d->rootProcess = new KProcess;
00362
00363 *d->rootProcess << kdesu;
00364 *d->rootProcess << "--nonewdcop" << "-n" << "-d" << QString( "-i%1" ).arg(moduleInfo().icon());
00365
00366 *d->rootProcess << QString("kcmshell %1 --embed-proxy %2 --lang %3").arg(cmd).arg
00367 (d->embedWidget->winId()).arg(KGlobal::locale()->language());
00368
00369 connect(d->rootProcess, SIGNAL(processExited(KProcess*)), SLOT(rootExited()));
00370
00371 if ( !d->rootProcess->start( KProcess::NotifyOnExit ))
00372 {
00373 d->rootMode = false;
00374 rootExited();
00375 }
00376 else
00377 {
00378 d->rootMode = true;
00379 kapp->dcopClient();
00380 d->rootCommunicator = new KCModuleProxyRootCommunicatorImpl( d->dcopName + "-RootCommunicator", this );
00381 }
00382
00383 delete lblBusy;
00384 QApplication::restoreOverrideCursor();
00385 return;
00386 }
00387
00388
00389 delete d->embedFrame;
00390 d->embedFrame = 0;
00391 delete d->embedWidget;
00392 d->embedWidget = 0;
00393 delete lblBusy;
00394
00395 QApplication::restoreOverrideCursor();
00396 }
00397
00398 void KCModuleProxy::rootExited()
00399 {
00400 kdDebug(711) << k_funcinfo << endl;
00401
00402 if ( d->embedWidget->embeddedWinId() )
00403 XDestroyWindow(qt_xdisplay(), d->embedWidget->embeddedWinId());
00404
00405 delete d->embedWidget;
00406 d->embedWidget = 0;
00407
00408 delete d->rootProcess;
00409 d->rootProcess = 0;
00410
00411 delete d->embedFrame;
00412 d->embedFrame=0;
00413
00414 delete d->rootCommunicator;
00415 d->rootCommunicator = 0;
00416
00417
00418 d->rootMode = false;
00419
00420 d->topLayout->invalidate();
00421
00422 QShowEvent ev;
00423 showEvent( &ev );
00424
00425 moduleChanged( false );
00426 emit childClosed();
00427 }
00428
00429 KCModuleProxy::~KCModuleProxy()
00430 {
00431 deleteClient();
00432 KCModuleLoader::unloadModule(moduleInfo());
00433
00434 delete d;
00435 }
00436
00437 void KCModuleProxy::deleteClient()
00438 {
00439 if( d->embedWidget )
00440 XKillClient(qt_xdisplay(), d->embedWidget->embeddedWinId());
00441
00442
00443 delete d->kcm;
00444 d->kcm = 0;
00445
00446 delete d->dcopObject;
00447 d->dcopObject = 0;
00448
00449 if( d->dcopClient && !d->dcopClient->detach() )
00450 kdDebug(711) << "Unregistering from DCOP failed." << endl;
00451
00452 delete d->dcopClient;
00453 d->dcopClient = 0;
00454
00455 kapp->syncX();
00456
00457 }
00458
00459 void KCModuleProxy::moduleChanged( bool c )
00460 {
00461 if( d->changed == c )
00462 return;
00463
00464 d->changed = c;
00465 emit changed( c );
00466 emit changed( this );
00467 }
00468
00469 void KCModuleProxy::moduleDestroyed()
00470 {
00471 d->kcm = 0;
00472 }
00473
00474 KCModuleProxy::KCModuleProxy( const KService::Ptr & service, bool withFallback,
00475 QWidget * parent, const char * name, const QStringList & args)
00476 : QWidget( parent, name )
00477 {
00478 init( KCModuleInfo( service ));
00479 d->args = args;
00480 d->withFallback = withFallback;
00481 }
00482
00483 KCModuleProxy::KCModuleProxy( const KCModuleInfo & info, bool withFallback,
00484 QWidget * parent, const char * name, const QStringList & args )
00485 : QWidget( parent, name )
00486 {
00487 init( info );
00488 d->args = args;
00489 d->withFallback = withFallback;
00490 }
00491
00492 KCModuleProxy::KCModuleProxy( const QString& serviceName, bool withFallback,
00493 QWidget * parent, const char * name,
00494 const QStringList & args)
00495 : QWidget( parent, name )
00496 {
00497 init( KCModuleInfo( serviceName ));
00498 d->args = args;
00499 d->withFallback = withFallback;
00500 }
00501
00502 void KCModuleProxy::init( const KCModuleInfo& info )
00503 {
00504 kdDebug(711) << k_funcinfo << endl;
00505
00506 d = new KCModuleProxyPrivate( info );
00507
00508
00509
00510
00511
00512
00513
00514 }
00515
00516 void KCModuleProxy::load()
00517 {
00518
00519 if( d->rootMode )
00520 callRootModule( "load()" );
00521 else if( realModule() )
00522 {
00523 d->kcm->load();
00524 moduleChanged( false );
00525 }
00526 }
00527
00528 void KCModuleProxy::save()
00529 {
00530 if( d->rootMode )
00531 callRootModule( "save()" );
00532 else if( d->changed && realModule() )
00533 {
00534 d->kcm->save();
00535 moduleChanged( false );
00536 }
00537 }
00538
00539 void KCModuleProxy::callRootModule( const QCString& function )
00540 {
00541 QByteArray sendData, replyData;
00542 QCString replyType;
00543
00544
00545
00546 if( !kapp->dcopClient()->call( d->dcopName, d->dcopName, function, sendData,
00547 replyType, replyData, true, -1 ))
00548 kdDebug(711) << "Calling function '" << function << "' failed." << endl;
00549
00550 }
00551
00552 void KCModuleProxy::defaults()
00553 {
00554 if( d->rootMode )
00555 callRootModule( "defaults()" );
00556 if( realModule() )
00557 d->kcm->defaults();
00558 }
00559
00560 QString KCModuleProxy::quickHelp() const
00561 {
00562
00563 if( !d->rootMode )
00564 return realModule() ? realModule()->quickHelp() : QString::null;
00565 else
00566 {
00567 QByteArray data, replyData;
00568 QCString replyType;
00569
00570 if (kapp->dcopClient()->call(d->dcopName, d->dcopName, "quickHelp()",
00571 data, replyType, replyData))
00572 kdDebug(711) << "Calling DCOP function bool changed() failed." << endl;
00573 else
00574 {
00575 QDataStream reply(replyData, IO_ReadOnly);
00576 if (replyType == "QString")
00577 {
00578 QString result;
00579 reply >> result;
00580 return result;
00581 }
00582 else
00583 kdDebug(711) << "DCOP function changed() returned mumbo jumbo." << endl;
00584 }
00585 return QString::null;
00586 }
00587 }
00588
00589 const KAboutData * KCModuleProxy::aboutData() const
00590 {
00591 if( !d->rootMode )
00592 return realModule() ? realModule()->aboutData() : 0;
00593 else
00594
00595
00596 return 0;
00597
00598
00599 }
00600
00601 int KCModuleProxy::buttons() const
00602 {
00603 return realModule() ? realModule()->buttons() :
00604 KCModule::Help | KCModule::Default | KCModule::Apply ;
00605 }
00606
00607 QString KCModuleProxy::rootOnlyMsg() const
00608 {
00609 return realModule() ? realModule()->rootOnlyMsg() : QString::null;
00610 }
00611
00612 bool KCModuleProxy::useRootOnlyMsg() const
00613 {
00614 return realModule() ? realModule()->useRootOnlyMsg() : true;
00615 }
00616
00617 KInstance * KCModuleProxy::instance() const
00618 {
00619 return realModule() ? realModule()->instance() : 0;
00620 }
00621
00622 bool KCModuleProxy::changed() const
00623 {
00624 return d->changed;
00625 }
00626
00627 const KCModuleInfo& KCModuleProxy::moduleInfo() const
00628 {
00629 return d->modInfo;
00630 }
00631
00632 bool KCModuleProxy::rootMode() const
00633 {
00634 return d->rootMode;
00635 }
00636
00637 QCString KCModuleProxy::dcopName() const
00638 {
00639 return d->dcopName;
00640 }
00641
00642 void KCModuleProxy::emitQuickHelpChanged()
00643 {
00644 emit quickHelpChanged();
00645 }
00646
00647
00648 #include "kcmoduleproxy.moc"
00649
00650