[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-18 6:30:30
Message-ID: 200403180730.30195.frans.englich () telia ! com
[Download RAW message or body]

On Wednesday 17 March 2004 19:42, Frans Englich wrote:
> On Tuesday 16 March 2004 14:27, Matthias Kretz wrote:

OK. This version should be bug free. Right..

(How can it be one almost always find the answer right after asking?)

Kontact works, Konqueror works, `kcmshell mouse kdm keyboard` works.

BTW, I have a question - is it possible to get a KServiceGroup::List of /all/ 
modules(belonging to base group "Settings/") regardless of what sub-group 
they belong to? Rephrased: A list containing all KCMs but no sub categories 
of Settings/.

 (kdebase/kcontrol/kcontrol/modules.cpp::readDesktopEntriesRecursive does it 
by recursing through each sub group)


			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	18 Mar 2004 06:13:31 -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 section require root access.</b><br>"
+                      "Click the \"Administrator Mode\" button to "
+                      "allow modifications."));
+
+    QWhatsThis::add(this, i18n("This section requires special permissions, probably \
" +		      "for system-wide changes. 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,332 @@ 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;
 };
+/***************************************************************/
+
+
+
+
+
+/***************************************************************/
+/**
+ * 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 = (moduleInfo().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);
+			 }
+	}
+
+	kdDebug() << "MODULE FILENAME = " << moduleInfo().fileName();
+	KService::Ptr s = moduleInfo().service();
+	if ( !s )
+	{
+		d->kcm = new KCMError( i18n("The module %1(the desktop file to be exact) could not \
be found.").arg( +					moduleInfo().fileName() ), that );
+	}
+	else if ( s->library().isEmpty() )
+	{
+		d->kcm = new KCMError( i18n("The specified library %1 could not be found.").arg(
+					moduleInfo().library() ), that );
+	}	
+	else /* "Prfft! Relax! Nothing to worry about!" */
+	{
+		QApplication::setOverrideCursor(Qt::WaitCursor);
+		d->kcm = KCModuleLoader::loadModule( moduleInfo(), 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 = moduleInfo().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();
+		}
+	}
 
-KCModuleProxy::KCModuleProxy( const KCModuleInfo & info, bool fallback,
+	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(moduleInfo());
+	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 +540,7 @@ void KCModuleProxy::load()
 
 void KCModuleProxy::save()
 {
-	if( d->kcm )
+	if( d->kcm && d->changed )
 	{
 		d->kcm->save();
 		moduleChanged( false );
@@ -124,56 +591,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	18 Mar 2004 06:13:31 -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,250 @@
 #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 does not take care of authorization of KCModules. \n
+ * KCModuleProxy do lazy loading, meaning the library will not be loaded or 
+ * any other initialization done before its show() function is called. This means 
+ * modules will only be loaded when they are actually needed as well as it is \
possible to  + * load many KCModuleProxy without any speed penalty.
+ *
+ * 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	18 Mar 2004 06:13:40 -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,10 +25,12 @@
 #include <qcursor.h>
 
 #include <klocale.h>
+#include <kstdguiitem.h>
 #include <kdebug.h>
 #include <kiconloader.h>
 #include <kmessagebox.h>
 #include <klibloader.h>
+#include <kapplication.h>
 #include <krun.h>
 #include <kprocess.h>
 #include <kaboutdata.h>
@@ -39,23 +42,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,17 +76,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();
+    init();
 }
 
 inline void KCMultiDialog::init()
 {
-    d = 0L;
+    showButton( User1, false );
+    showButton( User2, false );
     enableButton(Apply, false);
     connect(this, SIGNAL(aboutToShowPage(QWidget *)), this, \
SLOT(slotAboutToShow(QWidget *)));  setInitialSize(QSize(640,480));
@@ -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,9 +224,13 @@ void KCMultiDialog::addModule(const QStr
 void KCMultiDialog::addModule(const KCModuleInfo& moduleinfo,
         QStringList parentmodulenames, bool withfallback)
 {
+
     kdDebug(710) << "KCMultiDialog::addModule " << moduleinfo.moduleName() <<
         endl;
 
+    if ( !kapp->authorizeControlModule( moduleinfo.service()->menuId() ))
+            return;
+
     QFrame* page = 0;
     if (!moduleinfo.service()->noDisplay())
         switch( dialogface )
@@ -280,6 +296,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()
@@ -321,8 +342,6 @@ void KCMultiDialog::show()
 
 void KCMultiDialog::slotAboutToShow(QWidget *page)
 {
-    kdDebug( 710 ) << k_funcinfo << endl;
-    // honor KCModule::buttons
     QObject * obj = page->child( 0, "KCModuleProxy" );
     if( ! obj )
         return;
@@ -330,12 +349,37 @@ void KCMultiDialog::slotAboutToShow(QWid
             "KCModuleProxy" );
     if( ! module )
         return;
-    // TODO: if the dialogface is Plain we should hide the buttons instead of
-    // disabling
+    d->currentModule = module;
+
     enableButton( KDialogBase::Help,
-            module->buttons() & KCModule::Help );
+            d->currentModule->buttons() & KCModule::Help );
     enableButton( KDialogBase::Default,
-            module->buttons() & KCModule::Default );
+            d->currentModule->buttons() & KCModule::Default );
+
+    disconnect( this, SIGNAL(user2Clicked()), 0, 0);
+    /* Enable the Admin Mode button */
+    if (d->currentModule->moduleInfo().needsRootPrivileges())
+    {
+        enableButton( User2, true );
+        connect( this, SIGNAL(user2Clicked()), d->currentModule, SLOT( runAsRoot() \
)); +    }
+    else
+        enableButton( User2, false);
 }
 
+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	18 Mar 2004 06:13:40 -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