[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    Re: Extending KCModuleProxy
From:       Frans Englich <frans.englich () telia ! com>
Date:       2004-03-17 18:42:23
Message-ID: 200403171942.23812.frans.englich () telia ! com
[Download RAW message or body]

On Tuesday 16 March 2004 14:27, Matthias Kretz wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Hi Frans,
>
> first of all thank you for documenting the KCModuleProxy class.
>
> A few remarks on what I've seen (I've only looked through the diff - no
> testing done):
> - - Reading the diff was really hard because you reordered the code and
> changed the indenting. So I had to manually diff the old and new code :-(
> - - Please don't remove the vim modeline. People using vim automatically
> will use the right indentation style if it's present.

True, the thing is, kcmoduleproxy.diff is 24kb big and the kcmoduleproxy.
{cpp,h} is 21.2kb in total - the class is basically rewritten. realModule() is 
rewritten that's perhaps why it appears as moved(in total 99 lines removed, 
810 added). But I can run it through indent though, should I?

> - - The changed signal is not identical to the one of the embedded KCM. The
> changed signal of the proxy is only emitted if the KCM really changed. If
> changed() == true and the KCM emits changed(true) the proxy won't emit the
> changed signal.

Ok, that was my /intention/ too :)

Sorry, you will have to be a little bit more specific. in realModule() I do:

connect( d->kcm, SIGNAL( changed( bool ) ),
    SLOT(moduleChanged(bool)) );
 
And moduleChanged looks like this:

void KCModuleProxy::moduleChanged( bool c )
{
        if( d && d->changed != c )
        {
                d->changed = c;
                emit changed( c );
                emit changed( this );
        }
}


> - - there's an i18n call missing when creating the KCMError object

Fixed.

> - - The proxy was supposed to be really light weight. Just think of the
> Kontact config dlg which has sth. like 30 KCMs or so.
> The proxy makes lazy 
> loading easy and without a lot of overhead. The new implementation doesn't
> look very optimised on that regard (If I read correctly it even doesn't do
> lazy loading anymore). I'd like to see some numbers like how long it takes
> to create the Kontact config dlg.
>
> before I can continue to make usefull comments I'd need to know if you
> really did throw out lazy loading...
>
> JFYI: KCModuleProxy was supposed to do two things:
> 1. sane changed handling
> 2. easy lazy loading
> This is very different from what the ProxyWidget in KControl does so the
> idea never occured to me to merge the two.
KControl's ConfigModule do lazy loading on ProxyWidget(which loads ProxyView 
which loads a KCModule..). I would say the things KCModuleProxy is supposed 
to do, is of interest for all cases where KCModules are used(such as 
KControl).

Yes, lazy loading was thrown out in my patch but it's back now(AFAICT). It was 
easy to do - I merged realModule and init.

The removal was intentional because I thought 95% of the cases one module 
would be shown and the rest about 3-5 modules(configure dialogs). But since 
it back, twisted games like in Kontact is possible. FYI, Kontact without lazy 
loading is unacceptable slow.

New versions attached(kstdgui committed). kcmultidialog.cpp#351 crashes 
because KCModuleProxyPrivate* d; is not initialized. Which is really weird to 
me since I do it in KCMultiDialog's constructors, AFAICT.



Thanks,

		Frans




["kcmoduleproxy.diff" (text/x-diff)]

Index: kutils/kcmoduleproxy.cpp
===================================================================
RCS file: /home/kde/kdelibs/kutils/kcmoduleproxy.cpp,v
retrieving revision 1.2
diff -u -3 -p -r1.2 kcmoduleproxy.cpp
--- kutils/kcmoduleproxy.cpp	24 Jan 2004 20:28:02 -0000	1.2
+++ kutils/kcmoduleproxy.cpp	17 Mar 2004 18:13:19 -0000
@@ -1,4 +1,5 @@
 /*  This file is part of the KDE project
+    Copyright (C) 2004 Frans Englich <frans.englich@telia.com>
     Copyright (C) 2003 Matthias Kretz <kretz@kde.org>
 
     This library is free software; you can redistribute it and/or
@@ -14,24 +15,185 @@
     along with this library; see the file COPYING.LIB.  If not, write to
     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
     Boston, MA 02111-1307, USA.
-
 */
 
-#include "kcmoduleproxy.h"
-#include "kcmoduleloader.h"
-#include "kcmoduleinfo.h"
 #include <qlayout.h>
 #include <qapplication.h>
+#include <qlabel.h>
 #include <qcursor.h>
+#include <qpoint.h>
+#include <qlayout.h>
+#include <qframe.h>
+#include <qfileinfo.h>
+#include <qwhatsthis.h>
+#include <qwidget.h>
+#include <dcopclient.h>
+#include <qvbox.h>
+#include <qxembed.h>
+#include <qscrollview.h>
+
+#include <kdialog.h>
+#include <kuser.h>
+#include <kcmodule.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kprocess.h>
+#include <kservice.h>
+#include <kcmoduleloader.h>
+#include <kcmoduleinfo.h>
+
+#include <X11/Xlib.h>
+
+#include "kcmoduleproxy.h"
+#include "kcmoduleproxy.moc"
+
+/***************************************************************/
+class WhatsThis : public QWhatsThis
+{
+	public:
+		WhatsThis( KCModuleProxy* parent )
+			: QWhatsThis( parent ), proxy( parent ) {}
+
+		~WhatsThis(){};
+
+		QString text( const QPoint &  ) 
+		{
+			if ( !proxy->quickHelp().isEmpty() )
+				return proxy->quickHelp();
+			else
+			{
+				kdDebug() << "HEY! Your module does not have any quick help. Fix it!" << endl;
+				return i18n("The currently loaded configuration module.");
+			}
+		}
+
+	private:
+		KCModuleProxy* proxy;
+};
+/***************************************************************/
+
+
+
+
+
+
+/***************************************************************/
+/**
+ * The text you see at the top when a 
+ * module requires root access.
+ */
+class RootInfoWidget : public QLabel
+{
+public:
+    RootInfoWidget(QWidget *parent, const char *name);
+    void setRootMsg(const QString& s) { setText(s); }
+};
+
+RootInfoWidget::RootInfoWidget(QWidget *parent, const char *name = 0)
+    : QLabel(parent, name)
+{
+    setFrameShape(QFrame::Box);
+    setFrameShadow(QFrame::Raised);
+
+    setText(i18n("<b>Changes in this module require root access.</b><br>"
+                      "Click the \"Administrator Mode\" button to "
+                      "allow modifications in this module."));
 
+    QWhatsThis::add(this, i18n("This module requires special permissions, probably "
+		      "for system-wide modifications. Therefore it is "
+		      "required that you provide the root password to be "
+		      "able to change the modules properties. As long as "
+		      "you don't provide the password, the module will be "
+		      "disabled."));
+}
+/***************************************************************/
+
+
+
+
+
+
+/***************************************************************/
+class ProxyContentWidget : public QWidget
+{
+public:
+    ProxyContentWidget( QWidget* parent ) : QWidget( parent ) {}
+    ~ProxyContentWidget(){}
+
+    // this should be really done by qscrollview in AutoOneFit mode!
+    QSize sizeHint() const { return minimumSizeHint(); }
+};
+/***************************************************************/
+
+
+
+
+
+
+/***************************************************************/
+/**
+ * This is the wrapper closest to the real KCModule. It ensures the
+ * KCModule does not "explode" on small screens
+ * by encapsulating it in a qscrollview.
+ */
+class ProxyView : public QScrollView
+{
+public:
+	ProxyView::ProxyView(KCModule *client, QWidget *parent, bool run_as_root, const \
char *name) +		: QScrollView(parent, name)
+	{
+		setResizePolicy(QScrollView::AutoOneFit);
+		setFrameStyle( NoFrame );
+		QWidget* contentWidget = new ProxyContentWidget( viewport() );
+
+		QVBoxLayout* vbox = new QVBoxLayout( contentWidget );
+
+		if (run_as_root && client->useRootOnlyMsg()) // notify the user
+		{
+			RootInfoWidget *infoBox = new RootInfoWidget(contentWidget);
+			vbox->addWidget( infoBox );
+			QString msg = client->rootOnlyMsg();
+
+			if (!msg.isEmpty())
+				infoBox->setRootMsg(msg);
+				vbox->setSpacing(KDialog::spacingHint());
+		}
+
+		client->reparent(contentWidget,0,QPoint(0,0),true);
+		vbox->addWidget( client );
+		vbox->activate(); // Make sure we have a proper minimumSizeHint
+		addChild(contentWidget);
+	}
+
+private:
+	virtual void resizeEvent(QResizeEvent *e)
+	{
+		QScrollView::resizeEvent(e);
+	}
+};
+/***************************************************************/
+
+
+
+
+/***************************************************************/
 class KCModuleProxy::KCModuleProxyPrivate
 {
 	public:
 		KCModuleProxyPrivate( const KCModuleInfo & info )
-			: kcm( 0 )
-			, modinfo( info )
+			: args( 0 )
+			, kcm( 0 )
+			, view( 0 )
+			, embedWidget( 0 )
+			, rootProcess ( 0 )
+			, embedLayout ( 0 )
+			, embedFrame ( 0 )
+			, modInfo( info )
+			, withFallback( false )
 			, changed( false )
-			, failed( false )
+			, rootMode( false )
 		{}
 
 		~KCModuleProxyPrivate()
@@ -39,27 +201,330 @@ class KCModuleProxy::KCModuleProxyPrivat
 			delete kcm;
 		}
 
-		QStringList args;
-		KCModule * kcm;
-		KCModuleInfo modinfo;
-		bool withfallback;
+		/**
+		 * Used when loading the real module
+		 */
+		QStringList	args;
+
+		KCModule	*kcm;
+		QWidget		*view;
+		QXEmbed		*embedWidget;
+		KProcess	*rootProcess;
+		QVBoxLayout	*embedLayout;
+		QVBox		*embedFrame;
+
+		KCModuleInfo modInfo;
+		bool withFallback;
 		bool changed;
-		bool failed;
+		bool rootMode;
 };
+/***************************************************************/
+
 
-KCModuleProxy::KCModuleProxy( const KCModuleInfo & info, bool fallback,
+
+
+
+/***************************************************************/
+/**
+ * When something goes wrong in loading the module, this one 
+ * jumps in as a "dummy" module.
+ */
+class KCMError : public KCModule
+{
+	public:
+		KCMError( const QString& msg, QWidget* parent )
+			: KCModule( parent, "KCMError" )
+		{
+			QVBoxLayout* topLayout = new QVBoxLayout( this );
+			topLayout->addWidget( new QLabel( msg, this ) );
+		}
+};
+/***************************************************************/
+
+
+
+
+/***************************************************************/
+KCModule * KCModuleProxy::realModule() const
+{
+	if( d->kcm)
+		return d->kcm;
+
+	bool run_as_root = (d->modInfo.needsRootPrivileges() && !KUser().isSuperUser());
+	KCModuleProxy * that = const_cast<KCModuleProxy*>( this );
+
+	if ( run_as_root ) 
+	{
+		/* Try to make the root KCM have the same look as a regular one */
+		 QCString replyType;
+		 QByteArray replyData;
+		
+		if (kapp->dcopClient()->call("kcontrol", "moduleIface", "getPalette()", \
QByteArray(), +			 replyType, replyData) 
+			 && replyType == "QPalette") 
+			 {
+				 QDataStream reply( replyData, IO_ReadOnly );
+				 QPalette pal;
+				 reply >> pal;
+				 that->setPalette(pal);
+			 }
+		if (kapp->dcopClient()->call("kcontrol", "moduleIface", "getFont()", QByteArray(),
+				 replyType, replyData))
+			if ( replyType == "QFont") 
+			{
+				 QDataStream reply( replyData, IO_ReadOnly );
+				 QFont font;
+				 reply >> font;
+				 that->setFont(font);
+			 }
+	}
+
+	QString modName = QFileInfo(d->modInfo.fileName()).baseName();
+	KService::Ptr s = KService::serviceByDesktopName( modName );
+	if ( !s )
+	{
+		d->kcm = new KCMError( i18n("The module %1(the desktop file to be exact) could not \
be found.").arg( +					d->modInfo.fileName() ), that );
+	}
+	else if ( s->library().isEmpty() )
+	{
+		d->kcm = new KCMError( i18n("The specified library %1 could not be found.").arg(
+					d->modInfo.library() ), that );
+	}	
+	else /* "Prfft! Relax! Nothing to worry about!" */
+	{
+		QApplication::setOverrideCursor(Qt::WaitCursor);
+		d->kcm = KCModuleLoader::loadModule( modName, d->withFallback,
+			that, name(), d->args );
+		if( ! d->kcm )
+		{
+			d->kcm = new KCMError( i18n("There was an error when loading the module. "
+				"The desktop file as well as the library was found but "
+				"yet the module could not be loaded properly. Most likely "
+				"the factory declaration was wrong, or the "
+				"create_* function was missing."), that );
+			QApplication::restoreOverrideCursor();
+		}
+
+		connect( d->kcm, SIGNAL( changed( bool ) ),
+				SLOT(moduleChanged(bool)) );
+		connect( d->kcm, SIGNAL( destroyed() ),
+				SLOT( moduleDestroyed() ) );
+		connect( d->kcm, SIGNAL(quickHelpChanged()), 
+				SIGNAL(quickHelpChanged()));
+
+		QApplication::restoreOverrideCursor();
+	}
+
+	( new QHBoxLayout( that, 0, 0 ) )->setAutoAdd( true );
+	d->view = new ProxyView(d->kcm, that, run_as_root, "proxyview");
+	(void) new WhatsThis( that );
+
+	return d->kcm;
+}
+
+void KCModuleProxy::runAsRoot()
+{
+	if (!d->view || !moduleInfo().needsRootPrivileges() )
+		return;
+
+	delete d->rootProcess;
+	delete d->embedWidget;
+	delete d->embedLayout;
+
+	// create an embed widget that will embed the
+	// kcmshell running as root
+	d->embedLayout = new QVBoxLayout(d->view->parentWidget());
+	d->embedFrame = new QVBox( d->view->parentWidget() );
+	d->embedFrame->setFrameStyle( QFrame::Box | QFrame::Raised );
+	QPalette pal( red );
+	pal.setColor( QColorGroup::Background, 
+		d->view->parentWidget()->colorGroup().background() );
+	d->embedFrame->setPalette( pal );
+	d->embedFrame->setLineWidth( 2 );
+	d->embedFrame->setMidLineWidth( 2 );
+	d->embedLayout->addWidget(d->embedFrame,1);
+	d->embedWidget = new QXEmbed(d->embedFrame );
+	d->view->hide();
+	d->embedFrame->show();
+	QLabel *lblBusy = new QLabel(i18n("<big>Loading...</big>"), d->embedWidget);
+	lblBusy->setAlignment(AlignCenter);
+	lblBusy->setTextFormat(RichText);
+	lblBusy->setGeometry(0,0, d->view->width(), d->view->height());
+	lblBusy->show();
+
+	// prepare the process to run the kcmshell
+	QString cmd = d->modInfo.service()->exec().stripWhiteSpace();
+	bool kdeshell = false;
+	if (cmd.left(5) == "kdesu")
+	{
+		cmd = cmd.remove(0,5).stripWhiteSpace();
+
+		// remove all kdesu switches
+		while( cmd.length() > 1 && cmd[ 0 ] == '-' )
+		{
+			int pos = cmd.find( ' ' );
+			cmd = cmd.remove( 0, pos ).stripWhiteSpace();
+		}
+	}
+
+	if (cmd.left(8) == "kcmshell")
+	{
+		cmd = cmd.remove(0,8).stripWhiteSpace();
+		kdeshell = true;
+	}
+
+	// run the process
+	QString kdesu = KStandardDirs::findExe("kdesu");
+	if (!kdesu.isEmpty())
+	{
+		d->rootProcess = new KProcess;
+		*d->rootProcess << kdesu;
+		*d->rootProcess << "--nonewdcop";
+		// We have to disable the keep-password feature because
+		// in that case the modules is started through kdesud and kdesu
+		// returns before the module is running and that doesn't work.
+		// We also don't have a way to close the module in that case.
+		*d->rootProcess << "--n"; // Don't keep password.
+		if (kdeshell)
+		{
+			*d->rootProcess << QString("kcmshell %1 --embed %2 --lang %3").arg(cmd).arg
+				(d->embedWidget->winId()).arg(KGlobal::locale()->language());
+		}
+		else
+		{
+			*d->rootProcess << QString("%1 --embed %2 --lang %3").arg(cmd).arg
+				(d->embedWidget->winId()).arg( KGlobal::locale()->language() );
+		}
+
+		connect(d->rootProcess, SIGNAL(processExited(KProcess*)), SLOT(rootExited()));
+
+		if ( !d->rootProcess->start(KProcess::NotifyOnExit) )
+		{
+			d->rootMode = false;
+			rootExited();
+		}
+		else
+			d->rootMode = true;
+		delete lblBusy;
+		return;
+	}
+
+	/* Clean up in case of failure */
+	delete d->embedFrame;
+	d->embedFrame = 0;
+	delete d->embedWidget;
+	d->embedWidget = 0;
+	delete d->embedLayout;
+	d->embedLayout = 0;
+
+	d->view->show();
+}
+
+void KCModuleProxy::rootExited()
+{
+	if (d->embedWidget->embeddedWinId())
+		XDestroyWindow(qt_xdisplay(), d->embedWidget->embeddedWinId());
+
+	delete d->embedWidget;
+	d->embedWidget = 0;
+
+	delete d->rootProcess;
+	d->rootProcess = 0;
+
+	delete d->embedLayout;
+	d->embedLayout = 0;
+
+	delete d->embedFrame;
+	d->embedFrame=0;
+
+	d->view->show();
+	d->rootMode = false;
+	moduleChanged( false );
+	emit childClosed();
+
+}
+
+KCModuleProxy::~KCModuleProxy()
+{
+	deleteClient();
+	delete d;
+}
+
+void KCModuleProxy::deleteClient()
+{
+
+	if (d->embedWidget)
+		XKillClient(qt_xdisplay(), d->embedWidget->embeddedWinId());
+
+	delete d->rootProcess;
+	d->rootProcess = 0;
+
+	delete d->embedWidget;
+	d->embedWidget = 0;
+
+	delete d->embedFrame;
+	d->embedFrame = 0;
+	kapp->syncX();
+
+	delete d->view;
+	d->view = 0;
+
+	delete d->embedLayout;
+	d->embedLayout = 0;
+
+	KCModuleLoader::unloadModule(d->modInfo);
+	d->kcm = 0;
+
+}
+
+void KCModuleProxy::showEvent( QShowEvent * ev )
+{
+	( void )realModule();
+	QWidget::showEvent( ev );
+}
+
+void KCModuleProxy::moduleChanged( bool c )
+{
+	if( d && d->changed != c )
+	{
+		d->changed = c;
+		emit changed( c );
+		emit changed( this );
+	}
+}
+
+void KCModuleProxy::moduleDestroyed()
+{
+	d->kcm = 0;
+}
+
+KCModuleProxy::KCModuleProxy( const KService::Ptr & service, bool withFallback, 
+		QWidget  * parent, const char * name, const QStringList & args)
+	: QWidget( parent, name )
+	, d( new KCModuleProxyPrivate( KCModuleInfo( service )))
+{
+	d->args = args;
+	d->withFallback = withFallback;
+}
+
+KCModuleProxy::KCModuleProxy( const KCModuleInfo & info, bool withFallback,
 		QWidget * parent, const char * name, const QStringList & args )
 	: QWidget( parent, name )
 	, d( new KCModuleProxyPrivate( info ) )
 {
 	d->args = args;
-	d->withfallback = fallback;
+	d->withFallback = withFallback;
 }
 
-KCModuleProxy::~KCModuleProxy()
+KCModuleProxy::KCModuleProxy( const QString& serviceName, bool withFallback, 
+		QWidget * parent, const char * name, 
+		const QStringList & args)
+	: QWidget( parent, name )
+	, d( new KCModuleProxyPrivate( KCModuleInfo( serviceName )))
 {
-	KCModuleLoader::unloadModule( d->modinfo );
-	delete d;
+	d->args = args;
+	d->withFallback = withFallback;
 }
 
 void KCModuleProxy::load()
@@ -73,7 +538,7 @@ void KCModuleProxy::load()
 
 void KCModuleProxy::save()
 {
-	if( d->kcm )
+	if( d->kcm && d->changed )
 	{
 		d->kcm->save();
 		moduleChanged( false );
@@ -124,56 +589,14 @@ bool KCModuleProxy::changed() const
 	return d->changed;
 }
 
-KCModule * KCModuleProxy::realModule() const
-{
-	if( ! d->kcm && ! d->failed )
-	{
-		QApplication::setOverrideCursor(Qt::WaitCursor);
-		KCModuleProxy * that = const_cast<KCModuleProxy*>( this );
-		( new QHBoxLayout( that, 0, 0 ) )->setAutoAdd( true );
-		d->kcm = KCModuleLoader::loadModule( d->modinfo, d->withfallback,
-				that, name(), d->args );
-		if( ! d->kcm )
-		{
-			QApplication::restoreOverrideCursor();
-			KCModuleLoader::showLastLoaderError( that );
-			d->failed = true;
-			return 0;
-		}
-		connect( d->kcm, SIGNAL( changed( bool ) ),
-				this, SLOT( moduleChanged( bool ) ) );
-		connect( d->kcm, SIGNAL( destroyed() ),
-				this, SLOT( moduleDestroyed() ) );
-		QApplication::restoreOverrideCursor();
-	}
-	return d->kcm;
-}
-
 KCModuleInfo KCModuleProxy::moduleInfo() const
 {
-  return d->modinfo;
-}
-
-void KCModuleProxy::showEvent( QShowEvent * ev )
-{
-	( void )realModule();
-	QWidget::showEvent( ev );
-}
-
-void KCModuleProxy::moduleChanged( bool c )
-{
-	if( d->changed != c )
-	{
-		d->changed = c;
-		emit changed( c );
-	}
+	return d->modInfo;
 }
 
-void KCModuleProxy::moduleDestroyed()
+bool KCModuleProxy::rootMode() const
 {
-	d->kcm = 0;
+	return d->rootMode;
 }
 
-#include "kcmoduleproxy.moc"
-
-// vim: sw=4 ts=4 noet
+/***************************************************************/
Index: kutils/kcmoduleproxy.h
===================================================================
RCS file: /home/kde/kdelibs/kutils/kcmoduleproxy.h,v
retrieving revision 1.2
diff -u -3 -p -r1.2 kcmoduleproxy.h
--- kutils/kcmoduleproxy.h	24 Jan 2004 20:28:02 -0000	1.2
+++ kutils/kcmoduleproxy.h	17 Mar 2004 18:13:19 -0000
@@ -1,5 +1,6 @@
 /*  This file is part of the KDE project
     Copyright (C) 2003 Matthias Kretz <kretz@kde.org>
+    Copyright (C) 2004 Frans Englich <frans.englich@telia.com>
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -23,46 +24,244 @@
 #include <qwidget.h>
 #include <qstringlist.h>
 
+
+class KService;
 class KCModuleInfo;
 class KAboutData;
 class KInstance;
 class KCModule;
 
+/**
+ *
+ * @brief Encapsulates a @ref KCModule for embedding.
+ *
+ * @description @ref KCModuleProxy is a wrapper for KCModule intended for cases \
where  + * modules are to be displayed. It ensures layout is consistent, handles 
+ * root/administrator modules and in general takes care of the details 
+ * needed for making a module available in an interface. A KCModuleProxy 
+ * can be treated as a QWidget, without worrying about the details specific 
+ * for modules such as library loading. KCModuleProxy is not a sub class of KCModule \
 + * but its API closely resembles KCModule's.\n
+ * Usually, an instance is created by passing one of the constructors a @ref \
KService::Ptr,  + * @ref KCModuleInfo or simply the name of the module and then added \
to the layout as any  + * other widget. \n
+ * When the user have changed the module, @ref changed( bool ) as well as @ref \
changed ( KCModuleProxy * ) + * is emitted. KCModuleProxy does not take care of \
prompting for saving - if the object is deleted while  + * changes is not saved the \
changes will be lost. @ref changed() returns true if changes are unsaved. \n + * \n
+ * KCModuleProxy should be used in all cases where modules are embedded in order to 
+ * promote code efficiency and usability consistency.
+ * 
+ * @author Frans Englich <frans.englich@telia.com>
+ * @author Matthias Kretz <kretz@kde.org>
+ * @internal
+ *
+ */
 class KCModuleProxy : public QWidget
 {
-	Q_OBJECT
-	public:
-		KCModuleProxy( const KCModuleInfo & info, bool withfallback = false,
-				QWidget * parent = 0, const char * name = 0,
-				const QStringList & args = QStringList() );
-		~KCModuleProxy();
-		void load();
-		void save();
-		void defaults();
-		QString quickHelp() const;
-		const KAboutData * aboutData() const;
-		int buttons() const;
-		QString rootOnlyMsg() const;
-		bool useRootOnlyMsg() const;
-		KInstance * instance() const;
-		bool changed() const;
-		KCModule * realModule() const;
-    KCModuleInfo moduleInfo() const;
-
-	signals:
-		void changed( bool );
-
-	protected:
-		void showEvent( QShowEvent * );
-
-	private slots:
-		void moduleChanged( bool );
-		void moduleDestroyed();
-
-	private:
-		class KCModuleProxyPrivate;
-		KCModuleProxyPrivate * d;
+Q_OBJECT
+public:
+
+	/**
+	 * Constructs a KCModuleProxy from a KCModuleInfo class.
+	 *
+	 * @param info The KCModuleInfo to construct the module from.
+	 *
+	 * @param withfallback If set to true and loading of the module fails, 
+	 * a alternative will be tried, resulting in the module appearing in its 
+	 * own window, if at all.
+	 * The embedded module will be load()ed.
+	 *
+	 * @param args This is used in the implementation and is internal. Use the 
+	 * default.
+	 */
+	KCModuleProxy( const KCModuleInfo & info, bool withFallback = true,
+			QWidget * parent = 0, const char * name = 0,
+			const QStringList & args = QStringList() );
+
+	/**
+	 * Constructs a KCModuleProxy from a module's service name, which is 
+	 * equivalent to the desktop file for the kcm without the ".desktop" part. 
+	 * Otherwise equal to the one above.
+	 *
+	 * @param serviceName The module's service name to construct from.
+	 */
+	KCModuleProxy( const QString& serviceName, bool withFallback = true, 
+			QWidget * parent = 0, const char * name = 0,
+			const QStringList & args = QStringList() );
+			
+	/**
+	 * Constructs a KCModuleProxy from KService. Otherwise equal to the one above.
+	 *
+	 * @param service The KService to construct from.
+	 */
+	KCModuleProxy( const KService::Ptr& service, bool withFallback = true, 
+			QWidget  * parent = 0, const char * name = 0,
+			const QStringList & args = QStringList() );
+
+	/**
+	 * Default destructor
+	 */
+	~KCModuleProxy();
+
+	/**
+	 * Calling it will cause the contained module to 
+	 * run its load() routine.
+	 */
+	void load();
+
+	/**
+	 * Calling it will cause the contained module to 
+	 * run its save() routine.
+	 *
+	 * If the module was not modified, it will not be asked
+	 * to save.
+	 */
+	void save();
+
+	/**
+	 * @return the module's quickHelp();
+	 */
+	QString quickHelp() const;
+
+	/**
+	 * @return the module's aboutData()
+	 */
+	const KAboutData * aboutData() const;
+
+	/**
+	 * @return what buttons the module
+	 * needs
+	 */
+	int buttons() const;
+
+	/**
+	 * @return The module's custom root 
+	 * message, if it has one
+	 * @deprecated
+	 */
+	QString rootOnlyMsg() const KDE_DEPRECATED;
+	//KDE4 remove. There's a limit for convenience functions, 
+	// this one's available via moduleInfo()-> and realModule()->
+
+	/**
+	 * @return If the module is a root module.
+	 * @deprecated
+	 */
+	bool useRootOnlyMsg() const KDE_DEPRECATED;
+	//KDE4 remove. There's a limit for convenience functions, 
+	// this one's available via moduleInfo()-> and realModule()->
+
+	/**
+	 * Returns the embedded KCModule's KInstance.
+	 * @return The module's KInstance.
+	 * @deprecated
+	 */
+	KInstance * instance() const KDE_DEPRECATED;
+	//KDE4 remove. There's a limit for convenience functions, 
+	// this one's available via realModule()
+
+	/**
+	 * @return true if the module is modified 
+	 * and needs to be saved
+	 */
+	bool changed() const;
+
+	/**
+	 * Returns whether the module is running in root mode. A module is in root mode
+	 * when @ref runAsRoot() has been called. A session under root user will never \
reach  +	 * root mode.
+	 * @return true if the module is running with root privileges
+	 */
+	bool rootMode() const;
+
+	/**
+	 * @return the encapsulated module. 
+	 */
+	KCModule* realModule() const;
+
+	/**
+	 * @return a KCModuleInfo for the encapsulated
+	 * module
+	 */
+	KCModuleInfo moduleInfo() const;
+
+public slots:
+	
+	/**
+	 * Calling this will cause the module to be run in 
+	 * "administrator mode".
+	 *
+	 */
+	void runAsRoot();
+
+	/**
+	 * Calling it will cause the contained module to 
+	 * load its default values.
+	 */
+	void defaults();
+	
+signals:
+
+	/*
+	 * This signal is relayed from the encapsulated module, and 
+	 * is equivalent to the module's own changed(bool) signal.
+	 */
+	void changed( bool state );
+	
+	/**
+	 * This is emitted in the same situations as in the one above. Practical 
+	 * when several KCModuleProxys are loaded.
+	 */
+	void changed( KCModuleProxy* mod );
+
+	/**
+	 * When a module running with root privileges and exits, returns to normal mode, \
the  +	 * childClosed() signal is emitted.
+	 */
+	void childClosed();
+
+	/*
+	 * This signal is relayed from the encapsulated module, and 
+	 * is equivalent to the module's own quickHelpChanged() signal.
+	 */
+	void quickHelpChanged();
+
+protected:
+
+	/**
+	 * Reimplemented for internal purposes. Makes sure the encapsulated 
+	 * module is loaded before the show event is taken care of.
+	 */
+	void showEvent( QShowEvent * );
+
+private slots:
+
+	/**
+	 * This is called when the module exits from root mode. It zeroes 
+	 * pointers, deletes the embed window, etc.
+	 */
+	void rootExited();
+
+	/**
+	 * Makes sure the proper variables is set and signals are emited.
+	 */
+	void moduleChanged( bool );
+
+	/**
+	 * Zeroes d->kcm
+	 */
+	void moduleDestroyed();
+
+	/**
+	 * Exits root mode and unloads the module.
+	 */
+	void deleteClient();
+
+private:
+	class KCModuleProxyPrivate;
+	KCModuleProxyPrivate * d;
 };
 
-// vim: sw=4 ts=4 noet
 #endif // KCMODULEPROXY_H
+


["kcmultidialog.diff" (text/x-diff)]

Index: kutils/kcmultidialog.cpp
===================================================================
RCS file: /home/kde/kdelibs/kutils/kcmultidialog.cpp,v
retrieving revision 1.51
diff -u -3 -p -r1.51 kcmultidialog.cpp
--- kutils/kcmultidialog.cpp	24 Jan 2004 20:28:02 -0000	1.51
+++ kutils/kcmultidialog.cpp	17 Mar 2004 18:13:27 -0000
@@ -2,6 +2,7 @@
    Copyright (c) 2000 Matthias Elter <elter@kde.org>
    Copyright (c) 2003 Daniel Molkentin <molkentin@kde.org>
    Copyright (c) 2003 Matthias Kretz <kretz@kde.org>
+   Copyright (c) 2004 Frans Englich <frans.erglich.com>
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
@@ -24,6 +25,7 @@
 #include <qcursor.h>
 
 #include <klocale.h>
+#include <kstdguiitem.h>
 #include <kdebug.h>
 #include <kiconloader.h>
 #include <kmessagebox.h>
@@ -39,23 +41,33 @@
 #include <assert.h>
 #include <qlayout.h>
 
+class KCMultiDialog::KCMultiDialogPrivate
+{
+    public:
+        KCMultiDialogPrivate()
+            : hasRootKCM( false ), currentModule( 0 )
+
+            {}
+        bool hasRootKCM;
+        KCModuleProxy* currentModule;
+};
+
+ 
 KCMultiDialog::KCMultiDialog(QWidget *parent, const char *name, bool modal)
     : KDialogBase(IconList, i18n("Configure"), Help | Default |Cancel | Apply |
-            Ok | User1, Ok, parent, name, modal, true,
-            KGuiItem( i18n( "&Reset" ), "undo" ) )
-    , dialogface( IconList )
+            Ok | User1 | User2, Ok, parent, name, modal, true,
+            KStdGuiItem::reset(), KStdGuiItem::adminMode())
+    , dialogface( IconList ), d( new KCMultiDialogPrivate )
 {
-    showButton( User1, false );;
     init();
 }
 
 KCMultiDialog::KCMultiDialog( int dialogFace, const QString & caption, QWidget * \
                parent, const char * name, bool modal )
     : KDialogBase( dialogFace, caption, Help | Default | Cancel | Apply | Ok |
-            User1, Ok, parent, name, modal, true,
-            KGuiItem( i18n( "&Reset" ), "undo" ) )
-    , dialogface( dialogFace )
+            User1 | User2, Ok, parent, name, modal, true,
+            KStdGuiItem::reset(), KStdGuiItem::adminMode())
+    , dialogface( dialogFace ), d( new KCMultiDialogPrivate )
 {
-    showButton( User1, false );;
     init();
 }
 
@@ -63,16 +75,17 @@ KCMultiDialog::KCMultiDialog( int dialog
         const KGuiItem &user3, int buttonMask, const QString &caption,
         QWidget *parent, const char *name, bool modal )
     : KDialogBase( dialogFace, caption, buttonMask | Help | Default | Cancel |
-            Apply | Ok | User1, Ok, parent, name, modal, true,
-            KGuiItem( i18n( "&Reset" ), "undo" ), user2, user3 )
-    , dialogface( dialogFace )
+            Apply | Ok | User1 | User2 | User3, Ok, parent, name, modal, true,
+            KStdGuiItem::reset(), KStdGuiItem::adminMode(), user3 )
+    , dialogface( dialogFace ), d( new KCMultiDialogPrivate )
 {
-   showButton( User1, false );;
    init();
 }
 
 inline void KCMultiDialog::init()
 {
+    showButton( User1, false );
+    showButton( User2, false );
     d = 0L;
     enableButton(Apply, false);
     connect(this, SIGNAL(aboutToShowPage(QWidget *)), this, \
SLOT(slotAboutToShow(QWidget *))); @@ -197,7 +210,6 @@ void \
KCMultiDialog::clientChanged(bool s  
 void KCMultiDialog::addModule(const QString& path, bool withfallback)
 {
-    kdDebug(710) << "KCMultiDialog::addModule " << path << endl;
 
     KService::Ptr s = KService::serviceByStorageId(path);
     if (!s) {
@@ -212,6 +224,7 @@ void KCMultiDialog::addModule(const QStr
 void KCMultiDialog::addModule(const KCModuleInfo& moduleinfo,
         QStringList parentmodulenames, bool withfallback)
 {
+
     kdDebug(710) << "KCMultiDialog::addModule " << moduleinfo.moduleName() <<
         endl;
 
@@ -280,6 +293,11 @@ void KCMultiDialog::addModule(const KCMo
     cm.kcm = module;
     cm.service = moduleinfo.service();
     m_modules.append( cm );
+    if ( moduleinfo.needsRootPrivileges() && !d->hasRootKCM )
+    {
+        d->hasRootKCM = true;
+        showButton( User2, true );
+    }
 }
 
 void KCMultiDialog::removeAllModules()
@@ -330,12 +348,39 @@ void KCMultiDialog::slotAboutToShow(QWid
             "KCModuleProxy" );
     if( ! module )
         return;
+    d->currentModule = module;
+    //d->currentModule = ( KCModuleProxy* )obj->qt_cast( "KCModuleProxy" );
+    //if( ! d->currentModule )
+        //return;
     // TODO: if the dialogface is Plain we should hide the buttons instead of
     // disabling
     enableButton( KDialogBase::Help,
-            module->buttons() & KCModule::Help );
+            d->currentModule->buttons() & KCModule::Help );
     enableButton( KDialogBase::Default,
-            module->buttons() & KCModule::Default );
+            d->currentModule->buttons() & KCModule::Default );
+
+    /* Enable the Admin Mode button */
+    disconnect( 0, SIGNAL(user2Clicked()), 0, 0);
+    if (d->currentModule->moduleInfo().needsRootPrivileges())
+    {
+        enableButton( User2, true );
+        connect( this, SIGNAL(user2Clicked()), d->currentModule, SLOT( runAsRoot() \
)); +    }
 }
 
+void KCMultiDialog::slotUser2Clicked() /* Admin Mode */
+{
+    if ( !d->currentModule )
+        return;
+
+    enableButton( User2, false );
+    connect ( d->currentModule, SIGNAL( childClosed() ), SLOT( rootExit() ));
+}
+
+void KCMultiDialog::rootExit()
+{
+    enableButton( User2, true);
+}
+
+
 // vim: sw=4 et sts=4
Index: kutils/kcmultidialog.h
===================================================================
RCS file: /home/kde/kdelibs/kutils/kcmultidialog.h,v
retrieving revision 1.31
diff -u -3 -p -r1.31 kcmultidialog.h
--- kutils/kcmultidialog.h	15 Jan 2004 15:56:00 -0000	1.31
+++ kutils/kcmultidialog.h	17 Mar 2004 18:13:27 -0000
@@ -209,12 +209,20 @@ protected slots:
      **/
     virtual void slotHelp();
 
+    /**
+     * This slot is called when the user pressed the "Administrator Mode"
+     * button
+     */
+    virtual void slotUser2Clicked();
+
 private slots:
 
     void slotAboutToShow(QWidget *);
 
     void clientChanged(bool state);
 
+    void rootExit();
+
 private:
     void init();
     void apply();
@@ -234,7 +242,6 @@ private:
     QString _docPath;
     int dialogface;
 
-    // For future use
     class KCMultiDialogPrivate;
     KCMultiDialogPrivate *d;
 };



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic