Difference between revisions of "Development/Tutorials/Plasma/PackageStructure"

Jump to: navigation, search
(Created page with '==Abstract== PackageStructure defines what is in a Package. This information is used to create packages and provides a way to programatically refer to the contents. It's also use...')
 
m (Text replace - "<syntaxhighlight lang="make">" to "<syntaxhighlight lang="cmake">")
 
(30 intermediate revisions by 4 users not shown)
Line 1: Line 1:
==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.
PackageStructure defines what is in a Package. This information is used to create packages and provides a way to programatically refer to the contents. It's also used to provide an installation profile for you Packages.
+
 
==The plasmapkg==
+
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.
This tool is used to get information about Packages and install, remove or upgrade them. Run  
+
 
<code bash>
+
==plasmapkg==
 +
The plasmapkg command line tool is used to get information about Packages and install, remove or upgrade them. Run  
 +
<syntaxhighlight lang="bash">
 
plasmapkg --help
 
plasmapkg --help
</code>
+
</syntaxhighlight>
to get a list of available options.
+
to get a list of available options. The most commonly used options are
 +
{{path|-i}} for installing and {{path|-r}} for removing a package.
 +
 
 
==The Code==
 
==The Code==
 
===The Desktop File===
 
===The Desktop File===
 
Every PackageStructure needs a desktop file to tell plasma what package it's defining:
 
Every PackageStructure needs a desktop file to tell plasma what package it's defining:
 
'''plasma-packagestructure-test.desktop'''
 
'''plasma-packagestructure-test.desktop'''
<code ini>
+
<syntaxhighlight lang="ini">
 
[Desktop Entry]
 
[Desktop Entry]
 
Name=Test
 
Name=Test
Line 18: Line 22:
  
 
X-KDE-ServiceTypes=Plasma/PackageStructure
 
X-KDE-ServiceTypes=Plasma/PackageStructure
X-KDE-PluginInfo-Name=Plasma/Test
+
X-KDE-Library=plasma_packagestructure_myproject_test
X-KDE-Library=plasma_packagestructure_test
+
  
 
X-KDE-PluginInfo-Author=Farhad Hedayati Fard
 
X-KDE-PluginInfo-Author=Farhad Hedayati Fard
 
X-KDE-PluginInfo-Email=hf.farhad@gmail.com
 
X-KDE-PluginInfo-Email=hf.farhad@gmail.com
X-KDE-PluginInfo-Name=test
+
X-KDE-PluginInfo-Name=MyProject/Test
 
X-KDE-PluginInfo-Version=0.1
 
X-KDE-PluginInfo-Version=0.1
 
X-KDE-PluginInfo-Website=http://plasma.kde.org/
 
X-KDE-PluginInfo-Website=http://plasma.kde.org/
Line 30: Line 33:
 
X-Plasma-PackageFileFilter=*.test
 
X-Plasma-PackageFileFilter=*.test
 
X-Plasma-PackageFileMimetypes=application/zip
 
X-Plasma-PackageFileMimetypes=application/zip
</code>
+
</syntaxhighlight>
 
The most important fields are:
 
The most important fields are:
 
* Name, Comment and Type fields, which are required for all desktop files.
 
* 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-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).
+
* 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-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.
 
* X-KDE-PluginInfo-Name field which should be identical to the name of dataengine/plasmoid that uses this PackageStructure.
  
 
===The Header File===
 
===The Header File===
...testpackage.h...
+
'''testpackage.h'''
<code cppqt>
+
<syntaxhighlight lang="cpp-qt">
#ifndef TESTPACKAGE_H
+
#ifndef TESTPACKAGESTRUCTURE_H
#define TESTPACKAGE_H
+
#define TESTPACKAGESTRUCTURE_H
  
 
// We need this header since we are inheriting it
 
// We need this header since we are inheriting it
Line 48: Line 51:
  
 
/**
 
/**
  This PackageStructe provides an structure for packages used by the test  
+
  This PackageStructure provides an structure for packages used by the test  
 
  DataEngine.
 
  DataEngine.
 
*/
 
*/
class TestPackage : public Plasma::PackageStructure
+
class TestPackageStructure : public Plasma::PackageStructure
 
{
 
{
 
public:
 
public:
 
   // Every PackageStructure needs an explicit constructor with these arguments  
 
   // Every PackageStructure needs an explicit constructor with these arguments  
   explicit TestPackage( QObject *parent = 0, const QVariantList& args = QVariantList() );
+
   explicit TestPackageStructure(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(myproject_test, TestPackageStructure)
 
#endif // TESTPACKAGE_H
 
#endif // TESTPACKAGE_H
</code>
+
</syntaxhighlight>
 +
 
 +
===The Main Code===
 +
'''testpackage.cpp'''
 +
<syntaxhighlight lang="cpp-qt">
 +
#include "testpackage.h"
 +
 
 +
#include "plasma/applet.h"
 +
#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
 +
*/
 +
TestPackageStructure::TestPackageStructure(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-"));
 +
}
 +
</syntaxhighlight>
 +
 
 +
====Dynamic 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 reimplement the protect virtual method pathChanged, which is called whenever the path this PackageStructure is representing changes (including when first set), and set the extension of the script file, perhaps using code like this:
 +
<syntaxhighlight lang="cpp-qt">
 +
// 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;
 +
        }
 +
    }
 +
}
 +
</syntaxhighlight>
 +
 
 +
==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. Note that the name used in kde4_add_plugin must match the library name used in the .desktop file:
 +
<syntaxhighlight lang="cmake">
 +
set(testpackage_SRC testpackage.cpp)
 +
 
 +
kde4_add_plugin(plasma_packagestructure_myproject_test ${testpackage_SRC} )
 +
target_link_libraries(plasma_packagestructure_myproject_test ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS})
 +
install(TARGETS plasma_packagestructure_myproject_test DESTINATION ${PLUGIN_INSTALL_DIR})
 +
install(FILES plasma-packagestructure-myproject-test.desktop DESTINATION ${SERVICES_INSTALL_DIR})
 +
</syntaxhighlight>

Latest revision as of 11:20, 30 June 2011

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.

Contents

[edit] 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.

[edit] The Code

[edit] 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
X-KDE-PluginInfo-Email=hf.farhad@gmail.com
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.

[edit] The Header File

testpackage.h

#ifndef TESTPACKAGESTRUCTURE_H
#define TESTPACKAGESTRUCTURE_H
 
// We need this header since we are inheriting it
#include <plasma/packagestructure.h>
 
/**
 This PackageStructure provides an structure for packages used by the test 
 DataEngine.
*/
class TestPackageStructure : public Plasma::PackageStructure
{
public:
  // Every PackageStructure needs an explicit constructor with these arguments 
  explicit TestPackageStructure(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(myproject_test, TestPackageStructure)
#endif // TESTPACKAGE_H

[edit] The Main Code

testpackage.cpp

#include "testpackage.h"
 
#include "plasma/applet.h"
#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
*/
TestPackageStructure::TestPackageStructure(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-"));
}

[edit] Dynamic 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 reimplement the protect virtual method pathChanged, which is called whenever the path this PackageStructure is representing changes (including when first set), and set the extension of the script file, perhaps using code 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;
        }
    }
}

[edit] 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. Note that the name used in kde4_add_plugin must match the library name used in the .desktop file:

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

This page was last modified on 30 June 2011, at 11:20. This page has been accessed 5,373 times. Content is available under Creative Commons License SA 3.0 as well as the GNU Free Documentation License 1.2.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V.Legal