Difference between revisions of "Development/Tutorials/Services/Plugins (es)"

Jump to: navigation, search
m (Text replace - "<code cppqt>" to "<syntaxhighlight lang="cpp-qt">")
Line 21: Line 21:
 
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).
 
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).
  
<code cppqt>
+
<syntaxhighlight lang="cpp-qt">
 
#include <kdemacros.h>
 
#include <kdemacros.h>
 
#include <kxmlguiclient.h>
 
#include <kxmlguiclient.h>
Line 58: Line 58:
 
Aquí tenemos la implementación:
 
Aquí tenemos la implementación:
  
<code cppqt>
+
<syntaxhighlight lang="cpp-qt">
 
#include "plugin.h"
 
#include "plugin.h"
 
#include <KTextEdit>
 
#include <KTextEdit>
Line 98: Line 98:
 
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.
 
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.
  
<code cppqt>
+
<syntaxhighlight lang="cpp-qt">
 
#include <kdemacros.h>
 
#include <kdemacros.h>
 
#include <KPluginFactory>
 
#include <KPluginFactory>
Line 115: Line 115:
 
PLUGINLOADER.H
 
PLUGINLOADER.H
  
<code cppqt>
+
<syntaxhighlight lang="cpp-qt">
 
#include <QObject>
 
#include <QObject>
  
Line 138: Line 138:
 
PLUGINLOADER.CPP
 
PLUGINLOADER.CPP
  
<code cppqt>
+
<syntaxhighlight lang="cpp-qt">
 
#include "pluginloader.h"
 
#include "pluginloader.h"
  
Line 194: Line 194:
 
Vamos a asumir que tenemos un puntero a nuestro KTextEdit llamado simplemente editor.
 
Vamos a asumir que tenemos un puntero a nuestro KTextEdit llamado simplemente editor.
  
<code cppqt>
+
<syntaxhighlight lang="cpp-qt">
 
void MyMainWindow::loadPlugins()
 
void MyMainWindow::loadPlugins()
 
{
 
{
Line 206: Line 206:
 
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 :).
 
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 :).
  
<code cppqt>
+
<syntaxhighlight lang="cpp-qt">
 
void MyMainWindow::addPlugin(Plugin *plugin)
 
void MyMainWindow::addPlugin(Plugin *plugin)
 
{
 
{

Revision as of 20:30, 29 June 2011


Development/Tutorials/Services/Plugins


Creando y cargando Complementos usando KService
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).

<syntaxhighlight lang="cpp-qt">

  1. include <kdemacros.h>
  2. include <kxmlguiclient.h>
  3. 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:

<syntaxhighlight lang="cpp-qt">

  1. include "plugin.h"
  2. 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.

<syntaxhighlight lang="cpp-qt">

  1. include <kdemacros.h>
  2. include <KPluginFactory>
  3. include <KPluginLoader>
  1. 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

<syntaxhighlight lang="cpp-qt">

  1. include <QObject>
  1. 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

<syntaxhighlight lang="cpp-qt">

  1. include "pluginloader.h"
  1. include "plugin.h"
  1. include <KServiceTypeTrader>
  2. 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>

KPluginFactory no pudo cargar el complemento:
%1

</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.

<syntaxhighlight lang="cpp-qt"> 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 :).

<syntaxhighlight lang="cpp-qt"> 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.

Ejemplo de un complemento simple


Content is available under Creative Commons License SA 4.0 unless otherwise noted.