Development/Tutorials/Plasma4/ApplicationShell: Difference between revisions

    From KDE TechBase
    No edit summary
    (7 intermediate revisions by 2 users not shown)
    Line 2: Line 2:


    == The Shell ==
    == The Shell ==
    The core of the dashboard's logic is in a KPart in kdebase-runtime (''Currently still in playground/base/plasma/shells/kpart''), '''plasma-kpart'''. This KPart is loaded like any other ReadOnly KPart:
    The core of the dashboard's logic is in a KPart in kdebase-runtime called '''plasma-kpart'''. This KPart is loaded like any other ReadOnly KPart:
    <pre>
    <pre>
    // this routine will find and load our Part.  it finds the Part by
    // this routine will find and load our Part.  it finds the Part by
    Line 9: Line 9:
    KService::Ptr service = KService::serviceByDesktopPath( "plasma-kpart.desktop" );
    KService::Ptr service = KService::serviceByDesktopPath( "plasma-kpart.desktop" );


    if (service)
    if (service) {
    {
         // now that the Part is loaded, we cast it to a Part to get
         // now that the Part is loaded, we cast it to a Part to get
         // our hands on it
         // our hands on it
         m_part = service->createInstance<KParts::ReadOnlyPart>(0, args);
         m_part = service->createInstance<KParts::ReadOnlyPart>(0, args);
         if (m_part)
         if (m_part) {   
        {   
             // tell the KParts::MainWindow that this is indeed the main widget
             // tell the KParts::MainWindow that this is indeed the main widget
             // If you have something better to do with the widget, this is where
             // If you have something better to do with the widget, this is where
    Line 24: Line 22:
             createGUI(m_part);
             createGUI(m_part);


         }  
         } else {   
        else
        {   
             // For whatever reason the part didn't load
             // For whatever reason the part didn't load
             KMessageBox::error(this, i18n("Could not instantiate our Part!"));
             KMessageBox::error(this, i18n("Could not instantiate our Part!"));
             qApp->quit();
             qApp->quit();
         }   
         }   
    }  
    } else {   
    else
    {   
         // if we couldn't find our Part, we exit since the Shell by
         // if we couldn't find our Part, we exit since the Shell by
         // itself can't do anything useful
         // itself can't do anything useful
    Line 46: Line 40:
    == The Applets ==
    == The Applets ==
    There are two ways to approach writing applets, and some thought should go into this before writing your applets.  
    There are two ways to approach writing applets, and some thought should go into this before writing your applets.  
    The first is to use the standard method of writing Plasma applets, and provide a DataEngine which your applets can use to communicate with your application, either via DBus (allowing you to use the applets on the desktop and in other shells) or intra-process signal/slots using the PluginLoader infrastructure.
     
    === Plasma::Applet-based applets ===
    The first is to use the standard method of writing Plasma applets, and provide a DataEngine which your applets can use to communicate with your application, either via DBus (allowing you to use the applets on the desktop and in other shells) or intra-process signal/slots using a DataEngine provided by the [[#Communicating With Your Application|PluginLoader infrastructure]].
    * Pros:
    * Pros:
    ** Applets can be scripted in Javascript or Python
    ** Applets can be scripted in Javascript or Python
    ** Applets get all of the For Free benefits of being subclasses of Plasma::Applet
    ** Applets get all of the For Free benefits of being subclasses of Plasma::Applet
    * Cons:
    * Cons:
    ** Requires writing applets from scratc
    ** Requires writing applets from scratch
     


    The second method is to wrap QWidgets inside of a Plasma::Applet using a QGraphicsProxyWidget. This is most useful if your application has an existing  dashboard which is not based on Plasma.
    === QWidget-based Applets ===
    The second method is to wrap QWidgets inside of a Plasma::Applet using a QGraphicsProxyWidget. This is most useful if your application has an existing  dashboard which is not based on Plasma. These widgets would be created within your application, and loaded using the [[#Communicating With Your Application|PluginLoader infrastructure]].
    * Pros:
    * Pros:
    ** No need to learn a new API to build widgets
    ** No need to learn a new API to build widgets
    Line 61: Line 59:
    ** No Plasma theming
    ** No Plasma theming
    ** No access to DataEngines and other Plasma services
    ** No access to DataEngines and other Plasma services
    == Communicating With Your Application ==
    New in KDE Development Platform 4.6 is a class called Plasma::PluginLoader, a class which contains, unsurprisingly, most of Plasma's plugin loading logic. Plasma::Applet, Plasma::DataEngine, Plasma::Service, and Plasma::AbstractRunner all ask Plasma::PluginLoader to provide these plugins for them, and Plasma::PluginLoader can be subclassed for use by your application.
    Plasma::PluginLoader itself is a class with a mix of normal methods, static methods and protected virtual methods:
    * Plasma::* load* -- The main loading methods which are called by their respective classes in libplasma.
    * static void setPluginLoader() and static Plasma::PluginLoader* pluginLoader() -- These are the setters and getters of the application-specific subclass of Plasma::PluginLoader.
    * protected virtual internal* -- These are the methods which application-specific subclasses of Plasma::PluginLoader will implement. Their non-virtual counterparts call the application-specific implementations of these methods that are in the Plasma::PluginLoader specified by the application in setPluginLoader.
    The long and short of this is that application developers can inject their own Applets, DataEngines, Services and other Plasma objects into a Plasma shell and allow them to do things which plugins loaded through KDE's Plugin system could not do. Users of Plasma::PluginLoader also get many things for free, such as the easy loading and saving of applets, which would have to be done manually if an application chose to only use Plasma::Containment::addApplet().
    All that a developer needs to do is to subclass Plasma::PluginLoader and implement the internalAdd* methods which they want to provide plugins for.
    See [http://quickgit.kde.org/?p=kdeexamples.git&a=tree&h=c974192b5d47aa475e8fd0677c6ee8fdafe49158&hb=4459b79a52c3228a8a92ad2f169d406c244966da&f=plasma/c%20%20/kpart kdeexamples/plasma/c++/kpart] for an example of these communication methods.

    Revision as of 10:37, 13 July 2011

    This page looks at the steps it takes to embed a Plasma shell inside of your application as a dashboard or summary page.

    The Shell

    The core of the dashboard's logic is in a KPart in kdebase-runtime called plasma-kpart. This KPart is loaded like any other ReadOnly KPart:

    // this routine will find and load our Part.  it finds the Part by
    // name which is a bad idea usually.. but it's alright in this
    // case since our Part is made for this Shell
    KService::Ptr service = KService::serviceByDesktopPath( "plasma-kpart.desktop" );
    
    if (service) {
        // now that the Part is loaded, we cast it to a Part to get
        // our hands on it
        m_part = service->createInstance<KParts::ReadOnlyPart>(0, args);
        if (m_part) {   
            // tell the KParts::MainWindow that this is indeed the main widget
            // If you have something better to do with the widget, this is where
            // you would do it.
            setCentralWidget(m_part->widget());
    
            // and integrate the part's GUI with the shell's
            createGUI(m_part);
    
        }  else {   
            // For whatever reason the part didn't load
            KMessageBox::error(this, i18n("Could not instantiate our Part!"));
            qApp->quit();
        }   
    } else {   
        // if we couldn't find our Part, we exit since the Shell by
        // itself can't do anything useful
        KMessageBox::error(this, i18n("Could not find our Part!"));
        qApp->quit();
        // we return here, cause qApp->quit() only means "exit the
        // next time we enter the event loop...
        return;
    }
    

    The Applets

    There are two ways to approach writing applets, and some thought should go into this before writing your applets.

    Plasma::Applet-based applets

    The first is to use the standard method of writing Plasma applets, and provide a DataEngine which your applets can use to communicate with your application, either via DBus (allowing you to use the applets on the desktop and in other shells) or intra-process signal/slots using a DataEngine provided by the PluginLoader infrastructure.

    • Pros:
      • Applets can be scripted in Javascript or Python
      • Applets get all of the For Free benefits of being subclasses of Plasma::Applet
    • Cons:
      • Requires writing applets from scratch


    QWidget-based Applets

    The second method is to wrap QWidgets inside of a Plasma::Applet using a QGraphicsProxyWidget. This is most useful if your application has an existing dashboard which is not based on Plasma. These widgets would be created within your application, and loaded using the PluginLoader infrastructure.

    • Pros:
      • No need to learn a new API to build widgets
      • Closer integration with applications
      • Can re-use pre-existing applets
    • Cons:
      • No Plasma theming
      • No access to DataEngines and other Plasma services

    Communicating With Your Application

    New in KDE Development Platform 4.6 is a class called Plasma::PluginLoader, a class which contains, unsurprisingly, most of Plasma's plugin loading logic. Plasma::Applet, Plasma::DataEngine, Plasma::Service, and Plasma::AbstractRunner all ask Plasma::PluginLoader to provide these plugins for them, and Plasma::PluginLoader can be subclassed for use by your application. Plasma::PluginLoader itself is a class with a mix of normal methods, static methods and protected virtual methods:

    • Plasma::* load* -- The main loading methods which are called by their respective classes in libplasma.
    • static void setPluginLoader() and static Plasma::PluginLoader* pluginLoader() -- These are the setters and getters of the application-specific subclass of Plasma::PluginLoader.
    • protected virtual internal* -- These are the methods which application-specific subclasses of Plasma::PluginLoader will implement. Their non-virtual counterparts call the application-specific implementations of these methods that are in the Plasma::PluginLoader specified by the application in setPluginLoader.

    The long and short of this is that application developers can inject their own Applets, DataEngines, Services and other Plasma objects into a Plasma shell and allow them to do things which plugins loaded through KDE's Plugin system could not do. Users of Plasma::PluginLoader also get many things for free, such as the easy loading and saving of applets, which would have to be done manually if an application chose to only use Plasma::Containment::addApplet().

    All that a developer needs to do is to subclass Plasma::PluginLoader and implement the internalAdd* methods which they want to provide plugins for.

    See kdeexamples/plasma/c++/kpart for an example of these communication methods.