Development/Tutorials/Services/Plugins (es): Difference between revisions

    From KDE TechBase
    m (Text replace - "<code cppqt>" to "<syntaxhighlight lang="cpp-qt">")
    No edit summary
    (One intermediate revision by one other user not shown)
    Line 1: Line 1:
    {{Template:I18n/Language Navigation Bar|Development/Tutorials/Services/Plugins}}
     


    {{TutorialBrowser|
    {{TutorialBrowser|
    Line 52: Line 52:


    };
    };
    </code>
    </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:
    }
    }


    </code>
    </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") )  
    </code>
    </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);
    };
    };
    </code>
    </syntaxhighlight>


    PLUGINLOADER.CPP
    PLUGINLOADER.CPP
    Line 186: Line 186:
         }
         }
    }
    }
    </code>
    </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();
    }
    }
    </code>
    </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);
    }
    }
    </code>
    </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 ==

    Revision as of 12:09, 18 July 2012


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

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

    Ejemplo de un complemento simple