Development/Tutorials/Plasma4/PackageStructure: Difference between revisions

    From KDE TechBase
    Line 110: Line 110:
    </code>
    </code>
    ====File Definition====
    ====File Definition====
    in this Example, For simplicity's sake, I've added code/main.js file definition. This way your packages support only js scripts. But if you want to support a larger set of scripting languages, you should leave this to code/main, and then in your dataengine/plasmoid, when trying to use the installed packages, set the extension of the script file like this:
    For simplicity's sake, in this Example we've added code/main.js as the only file definition for the primary script file. With this approach, the package will only js scripts. If you want to support a larger set of scripting languages or allow the main script file to be defined within the package's metadata file, then the PackageStructure subclass should reimpliment the protect virtual method pathChanged and set the extension of the script file something like this:
    <code cppqt>
    <code cppqt>
    // get path to your installed packages
    // get path to your installed packages
    const QString path = KStandardDirs::locate( "data", QLatin1String( "plasma/test/" ) + pluginName + QLatin1Char( '/' ) );
    void TestPackageStructure::pathChanged()
    if (!path.isEmpty()) {
    {
         // pass path to the package and new TestPackage() as package type to Plasma::Package
        if (path().isEmpty()) {
         m_package = new Plasma::Package(path, packageStructure());
            return;
         if (m_package->isValid()) {
        }
             // get mainscript's file path (now code/main - without file extension)
            const QString mainscript = m_package->path() + m_package->structure()->contentsPrefix() +
         // Check if the Package developer was kind enough to tell us
            m_package->structure()->path( "mainscript" );
        // what script to use as the main script
            QFileInfo info( mainscript );
        KDesktopFile config(path() + "/metadata.desktop");
            // get supported scripting bindings, you'll find how to do this in kross tutorials.
        KConfigGroup cg = config.desktopGroup();
            QStringList extensions = supportedScriptLangs();
         QString mainScript = cg.readEntry("X-Plasma-MainScript", QString());
             // add supported extensions to the mainscript file path and check if it exists.
         if (!mainScript.isEmpty()) {
            for ( int i = 0; i < extensions.count() && !info.exists(); ++i ) {
             addFileDefinition("mainscript", mainScript, i18n("Main Script File"));
                 info.setFile( mainscript + extensions.value( i ) );
            setRequired("mainscript", true);
                 if (info.exists()) break;
            return;
            }
        }
            // if a supported script exists, use it!
     
            if ( info.exists() ) {
        // get mainscript's file path (now code/main - without file extension)
                m_action = new Kross::Action(this, pluginName);
        const QString mainscript = path() + "contents/code/main";
                m_action->setFile(info.filePath());
       
                  
      // iterate through supported scripting bindings.
                m_action->trigger();
      // you can learn how to retrieve such a list in Kross tutorials.
      foreach (const QString &extention, supportedScriptLangs()) {
             if (QFile::exists(mainscript + extension)) {
                 addFileDefinition("mainscript", mainScript + extension, i18n("Main Script File"));
                 setRequired("mainscript", true);
                 return;
             }
             }
         }
         }

    Revision as of 10:05, 17 March 2011

    Abstract

    A Plasma Package is a set of files, usually shipped in a single compressed archive, that together provide one particular data or functionality addon, such as Plasmoid or a Wallpaper set. Packages may be defined for any kind of custom data (e.g. non-compiled) addons. Packages can be installed, removed, listed and updated.

    Plasma::PackageStructure defines what is in a Package. This information is used to create packages and provides a way to programmatically refer to the contents. It's also used to provide an installation profile for your Packages.

    plasmapkg

    The plasmapkg command line tool is used to get information about Packages and install, remove or upgrade them. Run plasmapkg --help to get a list of available options. The most commonly used options are -i for installing and -r for removing a package.

    The Code

    The Desktop File

    Every PackageStructure needs a desktop file to tell plasma what package it's defining: plasma-packagestructure-test.desktop [Desktop Entry] Name=Test Comment=Test Package Structure Type=Service

    X-KDE-ServiceTypes=Plasma/PackageStructure X-KDE-Library=plasma_packagestructure_myproject_test

    X-KDE-PluginInfo-Author=Farhad Hedayati Fard [email protected] X-KDE-PluginInfo-Name=MyProject/Test X-KDE-PluginInfo-Version=0.1 X-KDE-PluginInfo-Website=http://plasma.kde.org/ X-KDE-PluginInfo-License=GPLv3+ X-KDE-PluginInfo-EnabledByDefault=true X-Plasma-PackageFileFilter=*.test X-Plasma-PackageFileMimetypes=application/zip The most important fields are:

    • Name, Comment and Type fields, which are required for all desktop files.
    • X-KDE-ServiceTypes field which tells plasma that this is a PackageStructure
    • X-KDE-PluginInfo-Name field which should be identical to the name used in your code (discussed later). This name must also be globally unique to all other PackageStructure plugins, and so using a name that includes unique components such as your project or organization's name is recommended to avoid naming collisions with other plugins.
    • X-KDE-Library field which tells plasma how to load/install the packages with this package structure.
    • X-KDE-PluginInfo-Name field which should be identical to the name of dataengine/plasmoid that uses this PackageStructure.

    The Header File

    testpackage.h

    1. ifndef TESTPACKAGE_H
    2. define TESTPACKAGE_H

    // We need this header since we are inheriting it

    1. include <plasma/packagestructure.h>

    /**

    This PackageStructure provides an structure for packages used by the test 
    DataEngine.
    
    • /

    class TestPackage : public Plasma::PackageStructure { public:

     // Every PackageStructure needs an explicit constructor with these arguments 
     explicit TestPackage(QObject *parent = 0, const QVariantList& args = QVariantList());
    

    };

    // This declares the plugin so it can be loaded at runtime from its shared library. // The class name is used as the second parameters. K_EXPORT_PLASMA_PACKAGESTRUCTURE(test, TestPackage)

    1. endif // TESTPACKAGE_H

    The Main Code

    testpackage.cpp

    1. include "testpackage.h"
    1. include "plasma/applet.h"
    2. include "plasma/package.h"

    /**

    We pass Plasma/Test as the type to the Plasma::PackageStructure. this string
    should be identical to the "X-KDE-PluginInfo-Name" in the desktop file,
    otherwise plasmapkg won't recognize your package and you'll get an this error
    when trying to install your packages:
    Could not find a suitable installer for package of type Plasma/Test
    
    • /

    TranslatorPackage::TranslatorPackage( QObject *parent, const QVariantList& args )

       : Plasma::PackageStructure(parent, QLatin1String("MyProject/Test"))
    

    {

       Q_UNUSED(args)
       // tell plasma about your package's directory structure with addDirectoryDefinition
       addDirectoryDefinition("images", QLatin1String("images"), i18n( Images") );
       // what does the directory contain?
       QStringList mimetypes;
       mimetypes << QLatin1String("image/svg+xml") << QLatin1String("image/png") << QLatin1String("image/jpeg");
       setMimetypes("images", mimetypes);
    
       addDirectoryDefinition("scripts", QLatin1String("code"), i18n("Executable Scripts"));
       mimetypes.clear();
       mimetypes << QLatin1String("text/*");
       setMimetypes("scripts", mimetypes);
       // tell plasma what is the name of script in the package.
       addFileDefinition("mainscript", QLatin1String("code/main.js"), i18n("Main Script File"));
    
       // tell plasma where to install your package.
       // normally this would be prepended with ~/.kde4/share/apps/
       // so the final path to your package after installation is ~/.kde4/share/apps/plasma/test/
       setDefaultPackageRoot(QLatin1String("plasma/test/"));
       // You'll need to use this service prefix when you want to access "test" packages.
       setServicePrefix(QLatin1String("plasma-test-"));
    

    }

    File Definition

    For simplicity's sake, in this Example we've added code/main.js as the only file definition for the primary script file. With this approach, the package will only js scripts. If you want to support a larger set of scripting languages or allow the main script file to be defined within the package's metadata file, then the PackageStructure subclass should reimpliment the protect virtual method pathChanged and set the extension of the script file something like this: // get path to your installed packages void TestPackageStructure::pathChanged() {

       if (path().isEmpty()) {
           return;
       }
    
       // Check if the Package developer was kind enough to tell us
       // what script to use as the main script
       KDesktopFile config(path() + "/metadata.desktop");
       KConfigGroup cg = config.desktopGroup();
       QString mainScript = cg.readEntry("X-Plasma-MainScript", QString());
       if (!mainScript.isEmpty()) {
           addFileDefinition("mainscript", mainScript, i18n("Main Script File"));
           setRequired("mainscript", true);
           return;
       }
    
       // get mainscript's file path (now code/main - without file extension)
       const QString mainscript = path() + "contents/code/main";
       
      // iterate through supported scripting bindings.
      // you can learn how to retrieve such a list in Kross tutorials.
      foreach (const QString &extention, supportedScriptLangs()) {
           if (QFile::exists(mainscript + extension)) {
               addFileDefinition("mainscript", mainScript + extension, i18n("Main Script File"));
               setRequired("mainscript", true);
               return;
           }
       }
    

    }

    Build and Install

    the CMakeLists.txt file tells cmake how to build and install your project, add the following lines to this file to for this test project: set(testpackage_SRC testpackage.cpp)

    kde4_add_plugin( plasma-packagestructure-test ${testpackage_SRC} ) target_link_libraries( plasma-packagestructure-test ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} ) install( TARGETS plasma-packagestructure-test DESTINATION ${PLUGIN_INSTALL_DIR} ) install( FILES plasma-packagestructure-test.desktop DESTINATION ${SERVICES_INSTALL_DIR} )