Development/Tutorials/Services/Plugins (es): Difference between revisions
Neverendingo (talk | contribs) m (Text replace - "<code cppqt>" to "<syntaxhighlight lang="cpp-qt">") |
({{Proposed_deletion|reason=Page was created before the current translation system.}}) |
||
(2 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
{{ | {{Proposed_deletion|reason=Page was created before the current translation system.}} | ||
{{TutorialBrowser| | {{TutorialBrowser| | ||
Line 52: | Line 52: | ||
}; | }; | ||
</ | </syntaxhighlight> | ||
Esta clase base dará los punteros necesarios para cada complemento que le permitan manipular los datos de la aplicación principal. En este caso, sólo damos acceso a la interfaz del editor principal a través de editorInterface(). | Esta clase base dará los punteros necesarios para cada complemento que le permitan manipular los datos de la aplicación principal. En este caso, sólo damos acceso a la interfaz del editor principal a través de editorInterface(). | ||
Line 90: | Line 90: | ||
} | } | ||
</ | </syntaxhighlight> | ||
Donde plugin.h es el archivo cabecera visto anteriormente. | Donde plugin.h es el archivo cabecera visto anteriormente. | ||
Line 106: | Line 106: | ||
K_PLUGIN_FACTORY( TextEditorFactory, registerPlugin< c >(); ) \ | K_PLUGIN_FACTORY( TextEditorFactory, registerPlugin< c >(); ) \ | ||
K_EXPORT_PLUGIN( TextEditorFactory("c") ) | K_EXPORT_PLUGIN( TextEditorFactory("c") ) | ||
</ | </syntaxhighlight> | ||
Esta macro simplemente unifica dos macros de KDE que nos permiten la exportación del complemento. | Esta macro simplemente unifica dos macros de KDE que nos permiten la exportación del complemento. | ||
Line 134: | Line 134: | ||
void pluginLoaded(Plugin * plugin); | void pluginLoaded(Plugin * plugin); | ||
}; | }; | ||
</ | </syntaxhighlight> | ||
PLUGINLOADER.CPP | PLUGINLOADER.CPP | ||
Line 186: | Line 186: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
El código mostrado simplemente pregunta a SyCoCa por un complemento para el TextEditor. Cuando creamos un complemento, se provee un archivo .desktop junto con el Tipo de Service para el cual el complemento está diseñado. Veremos más tarde cómo establecer un Tipo de Servicio adecuado a nuestro propio complemento. Emitimos la señal pluginLoaded cuando el complemento está cargado correctamente de forma que la aplicación lo integre en la interfaz gráfica. | El código mostrado simplemente pregunta a SyCoCa por un complemento para el TextEditor. Cuando creamos un complemento, se provee un archivo .desktop junto con el Tipo de Service para el cual el complemento está diseñado. Veremos más tarde cómo establecer un Tipo de Servicio adecuado a nuestro propio complemento. Emitimos la señal pluginLoaded cuando el complemento está cargado correctamente de forma que la aplicación lo integre en la interfaz gráfica. | ||
Line 201: | Line 201: | ||
pluginLoader->loadAllPlugins(); | pluginLoader->loadAllPlugins(); | ||
} | } | ||
</ | </syntaxhighlight> | ||
Si con este trozo de código hemos preguntado a PluginLoader que cargue todos los complementos y llamado al slot pluginLoaded, ahora implementaremos los complementos en la interfaz. | Si con este trozo de código hemos preguntado a PluginLoader que cargue todos los complementos y llamado al slot pluginLoaded, ahora implementaremos los complementos en la interfaz. | ||
Line 212: | Line 212: | ||
guiFactory()->addClient(plugin); | guiFactory()->addClient(plugin); | ||
} | } | ||
</ | </syntaxhighlight> | ||
Como nuestro complemento hereda de KXMLGuiClient, podemos usar cualquier tipo de interfaz gráfica cliente y KDE lo cargará automáticamente en nuestra aplicación. Por tanto, este pequeño código simplemente integra nuestro complemento con la ventana principal. | Como nuestro complemento hereda de KXMLGuiClient, podemos usar cualquier tipo de interfaz gráfica cliente y KDE lo cargará automáticamente en nuestra aplicación. Por tanto, este pequeño código simplemente integra nuestro complemento con la ventana principal. | ||
== Ejemplo de un complemento simple == | == Ejemplo de un complemento simple == |
Latest revision as of 20:13, 11 October 2023
Proposed for Deletion |
---|
This page has been proposed for deletion for the following reason:
|
Tutorial Series | Services |
Previous | Traders: Querying the System |
What's Next | n/a |
Further Reading | n/a |
Resumen
Antes de empezar con el código, vamos a ver qué ventajas podemos obtener desarrollando una aplicación estructurada en complementos (plugins). Primero de todo, una aplicación capaz de manejar complementos puede extender su funcionalidad sin límites aparentes. No obstante, en lugar de desarrollar un aplicación estructurada en complementos porque "es muy guay!!", el desarrollador debería pensar en las ventajas reales de este tipo de desarrollos. Por ejemplo podemos pensar en una aplicación que maneja archivos: el programa principal delega la creación/extracción/edición de cada tipo de archivo al complemento específico. De esta manera conseguimos modularidad en la aplicación, de forma que soportar nuevos tipos de archivos en el futuro consistirá simplemente en escribir el complemento específico y no en reescribir la aplicación. Bien, dejemos de hablar... y empecemos a programar =).
Ejemplo del Editor de Textos
Aunque una aplicación de manejo de archivos sería resultaría más bonita, aquí examinaremos un editor de textos simple capaz de cargar complementos. Cada complemento proveerá simplemente una característica nueva para la edición de texto.
Creando una clase como Interfaz de Complementos
El paso principal para crear una estructura de complementos es definir su clase base. Esta clase será heredada por cada complemento y debería dar acceso a los recursos de la aplicación principal. En este ejemplo la clase principal de un complemento heredará un KXMLGUIClient, ya que cada complemento dará acceso a sus añadidos a través de un elemento gráfico (un KAction en este caso).
#include <kdemacros.h>
#include <kxmlguiclient.h>
#include <QObject>
class KTextEdit;
class KDE_EXPORT Plugin : public QObject , public KXMLGUIClient
{
Q_OBJECT
public:
Plugin(QObject *parent);
virtual ~Plugin();
/**
* @return KTextEdit apunta al control de edición de la aplicación principal
*/
KTextEdit* editorInterface();
/**
* @internal Usado por la aplicación principal para establecer correctamente el editor.
* No llamar desde la reimplementación.
*/
void setEditorInterface(KTextEdit *);
private:
class PluginPrivate;
PluginPrivate *d;
};
Esta clase base dará los punteros necesarios para cada complemento que le permitan manipular los datos de la aplicación principal. En este caso, sólo damos acceso a la interfaz del editor principal a través de editorInterface().
Aquí tenemos la implementación:
#include "plugin.h"
#include <KTextEdit>
class Plugin::PluginPrivate {
public:
PluginPrivate(Plugin *q):
q(q),
m_editor(0){}
Plugin *q;
KTextEdit *m_editor;
};
Plugin::Plugin(QObject *parent) : QObject(parent),
d(new PluginPrivate(this))
{}
Plugin::~Plugin()
{}
KTextEdit* Plugin::editorInterface()
{
return d->m_editor;
}
void Plugin::setEditorInterface(KTextEdit *editor)
{
d->m_editor = editor;
}
Donde plugin.h es el archivo cabecera visto anteriormente. El método setEditorInterface permite a la aplicación principal establecer el puntero al KTextEditor. De esta forma, cada programador será capaz de acceder a la interfaz del editor de textos principal con él.
La Macro de la fábrica de complementos
Cada complemento estará "visible y disponible" a través del uso de una macro. Por tanto, mejor poner esta macro en nuestro propio myplugin_macros.h como sigue.
#include <kdemacros.h>
#include <KPluginFactory>
#include <KPluginLoader>
#define TEXTEDITOR_PLUGIN_EXPORT( c ) \
K_PLUGIN_FACTORY( TextEditorFactory, registerPlugin< c >(); ) \
K_EXPORT_PLUGIN( TextEditorFactory("c") )
Esta macro simplemente unifica dos macros de KDE que nos permiten la exportación del complemento.
Material para la carga de complementos
Ahora preparémonos para hacer a nuestra aplicación encontrar y cargar todos los complementos compatibles. Haremos uso de un ayudante que usa los métodos estándar de KDE para localizar y cargar complementos. Aquí tenemos la cabecera e implementación.
PLUGINLOADER.H
#include <QObject>
#include "plugintest_macros.h"
class Plugin;
class PluginLoader : public QObject
{
Q_OBJECT
public:
PluginLoader(QObject * parent);
virtual ~PluginLoader();
void loadAllPlugins();
signals:
void pluginLoaded(Plugin * plugin);
};
PLUGINLOADER.CPP
#include "pluginloader.h"
#include "plugin.h"
#include <KServiceTypeTrader>
#include <KDebug>
PluginLoader::PluginLoader(QObject * parent)
: QObject(parent)
{
}
PluginLoader::~PluginLoader()
{
}
void PluginLoader::loadAllPlugins()
{
kDebug() << "Cargar todos los complementos";
KService::List offers = KServiceTypeTrader::self()->query("TextEditor/Plugin");
KService::List::const_iterator iter;
for(iter = offers.begin(); iter < offers.end(); ++iter)
{
QString error;
KService::Ptr service = *iter;
KPluginFactory *factory = KPluginLoader(service->library()).factory();
if (!factory)
{
//KMessageBox::error(0, i18n("<html><p>KPluginFactory no pudo cargar el complemento:<br/><i>%1</i></p></html>",
// service->library()));
kError(5001) << "KPluginFactory no pudo cargar el complemento:" << service->library();
continue;
}
Plugin *plugin = factory->create<Plugin>(this);
if (plugin) {
kDebug() << "Cargar complemento:" << service->name();
emit pluginLoaded(plugin);
} else {
kDebug() << error;
}
}
}
El código mostrado simplemente pregunta a SyCoCa por un complemento para el TextEditor. Cuando creamos un complemento, se provee un archivo .desktop junto con el Tipo de Service para el cual el complemento está diseñado. Veremos más tarde cómo establecer un Tipo de Servicio adecuado a nuestro propio complemento. Emitimos la señal pluginLoaded cuando el complemento está cargado correctamente de forma que la aplicación lo integre en la interfaz gráfica.
Manejo de los complementos por la aplicación principal
Mostraré trozos de código que manejan la carga de complementos en la ventana principal. Vamos a asumir que tenemos un puntero a nuestro KTextEdit llamado simplemente editor.
void MyMainWindow::loadPlugins()
{
PluginLoader *loader = new PluginLoader(this);
connect(loader, SIGNAL(pluginLoaded(Plugin*)), this, SLOT(addPlugin(Plugin*)));
pluginLoader->loadAllPlugins();
}
Si con este trozo de código hemos preguntado a PluginLoader que cargue todos los complementos y llamado al slot pluginLoaded, ahora implementaremos los complementos en la interfaz. El método loadPlugins, se supone, es llamado al principio de la aplicación para cargar todo antes que el usuario pueda comenzar a usarlo. Por supuesto puedes decidir qué hacer con tus complementos e ignorar esta sugerencia :).
void MyMainWindow::addPlugin(Plugin *plugin)
{
plugin->setEditorInterface(editor);
guiFactory()->addClient(plugin);
}
Como nuestro complemento hereda de KXMLGuiClient, podemos usar cualquier tipo de interfaz gráfica cliente y KDE lo cargará automáticamente en nuestra aplicación. Por tanto, este pequeño código simplemente integra nuestro complemento con la ventana principal.