Development/Tutorials/Plasma4/JavaScript/DataEngine: Difference between revisions

From KDE TechBase
m (moved Development/Tutorials/Plasma/QtScript/DataEngine to Development/Tutorials/Plasma/JavaScript/DataEngine: Use the term "JavaScript" rather than "QtScript", because that's the term users know)
 
(12 intermediate revisions by 6 users not shown)
Line 1: Line 1:
== Abstract ==
{{TutorialBrowser|


Now that you've [[Development/Tutorials/Plasma/QtScript/GettingStarted|seen how to create a QtScript plasmoid]], we're going to move on to getting data into it.
series=JavaScript Plasmoids|


Plasma has a data abstraction mechanism called data engines.  You can ask for a data engine (by name), request a source from it (again, by name) and you get data back from it, usually either at fixed intervals or whenever it is updated.  The data is a map (which is the same as an object in QtScript).
name=Getting Data|


In this example, we'll get the local time from the time engine.
pre=[[../GettingStarted|Getting Started: Creating and running your first plasmoid in JavaScript]]|


next=[[../NowPlaying|Now Playing: Advanced DataEngine Usage Example]]|


== Metadata.desktop ==
reading=[[../API|JavaScript Plasmoid API reference]]
}}


Create a directory for your plasmoid, and create a <tt>metadata.desktop</tt> file with the following contents (replacing the author and email information):
== Abstract ==


<code ini>
Now that you've [[Development/Tutorials/Plasma/JavaScript/GettingStarted|seen how to create a JavaScript plasmoid]], we're going to move on to getting data into it.
[Desktop Entry]
Name=Yet Another Clock
Comment=An example QtScript widget
Icon=chronometer


Type=Service
Plasma has a data abstraction mechanism called DataEngines. You can ask for a DataEngine by name, request a source from it (again, by name) and you get data back from it, either at fixed intervals or whenever it is updated by the DataEngine internally. The data is a map (which is the same as an object in JavaScript) of string keys to data.
X-KDE-ServiceTypes=Plasma/Applet
 
X-Plasma-API=javascript
X-Plasma-MainScript=code/main.js
X-Plasma-DefaultSize=200,100
 
X-KDE-PluginInfo-Author=<Your name here>
X-KDE-PluginInfo-Email=<Your email here>
X-KDE-PluginInfo-Name=yet-another-clock
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-Website=http://plasma.kde.org/
X-KDE-PluginInfo-Category=Examples
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
</code>
 
For an explanation of these lines, see [[Development/Tutorials/Plasma/QtScript/GettingStarted|the getting started tutorial]].


In this example, we'll get the local time from the time engine.


== Main script ==
== Connecting Engines to plasmoid.dataUpdated ==


Create a <tt>contents/code/main.js</tt> file with the following contents:
Our <tt>contents/code/main.js</tt> will have the following content:


<code>
<syntaxhighlight lang="javascript">
layout = new LinearLayout(plasmoid);
layout = new LinearLayout(plasmoid);


Line 49: Line 30:
layout.addItem(label);
layout.addItem(label);


plasmoid.dataUpdate = function(name, data) {
plasmoid.dataUpdated = function(name, data) {
label.text = data.Time;
label.text = data.Time;
}
}


plasmoid.dataEngine("time").connectSource("Local", plasmoid, 500);
dataEngine("time").connectSource("Local", plasmoid, 500);
</code>
</syntaxhighlight>


There are two new things in this plasmoid.  We've implemented <tt>plasmoid.dataUpdate</tt>, and connected a data engine source to it.
There are two new things in this plasmoid.  We've implemented <tt>plasmoid.dataUpdated</tt>, and connected a data engine source to it.


If you connect a data engine source to <tt>object</tt>, when there is an update for that source the method <tt>object.dataUpdate</tt> is called with two arguments: the name of the source and a map containing the data provided by the source.
If you connect a data engine source to <tt>object</tt>, when there is an update for that source the method <tt>object.dataUpdated</tt> is called with two arguments: the name of the source and a map containing the data provided by the source.


In this case, <tt>plasmoid.dataUpdate</tt> gets called with <tt>"Local"</tt> as the first argument and the following object as the second argument (on my machine right now):
In this case, <tt>plasmoid.dataUpdated</tt> gets called with <tt>"Local"</tt> as the first argument and the following object as the second argument (on my machine right now):
<code>
<syntaxhighlight lang="javascript">
{
{
     Timezone_Continent: 'Europe',
     Timezone_Continent: 'Europe',
Line 69: Line 50:
     Timezone_City: 'Guernsey'
     Timezone_City: 'Guernsey'
}
}
</code>
</syntaxhighlight>


The last line of the script does the actual connection.  We select the <tt>"time"</tt> data engine and request the <tt>"Local"</tt> source from it, which provide the local time.  We tell it to connect to the <tt>plasmoid</tt> object and force an update every 500ms (every half a second).
The last line of the script does the actual connection.  We select the <tt>"time"</tt> data engine and request the <tt>"Local"</tt> source from it, which provide the local time.  We tell it to connect to the <tt>plasmoid</tt> object and force an update every 500ms (every half a second).
Line 75: Line 56:
If we left off the last parameter to <tt>connectSource</tt> (ie: didn't provide an update interval), then the source would be updated when there was new data available.  This doesn't make much sense for a clock, where the time is continually changing, so would actually get no updates at all if you did this.  However, there are other data engines (such as the "soliddevice" engine) where you only want to be notified when something changed, and in this case you would leave off the update interval.
If we left off the last parameter to <tt>connectSource</tt> (ie: didn't provide an update interval), then the source would be updated when there was new data available.  This doesn't make much sense for a clock, where the time is continually changing, so would actually get no updates at all if you did this.  However, there are other data engines (such as the "soliddevice" engine) where you only want to be notified when something changed, and in this case you would leave off the update interval.


=== Pro tip: plasmaengineexplorer ===
== Connecting Engines to Plasma Interface Elements ==
A number of Plasma interface elements support connecting DataEngines directly to them. These include:
 
* Label
* Meter
* TextEdit
 
With these widgets, one can simply direct the DataEngine to update the widget directly and it will attempt to display the data. So in our example we could also write it as:
 
 
<syntaxhighlight lang="javascript">
layout = new LinearLayout(plasmoid);
 
label = new Label();
layout.addItem(label);
 
dataEngine("time").connectSource("Local", label, 500);
</syntaxhighlight>
 
While this is not as flexible as implementing <tt>plasmoid.dataUpdated</tt>, it can be a useful technique.
 
== Connecting Engines to Arbitrary Functions ==
 
It is also possible to connect DataEngines to any Javascript function by passing it in as an argument to connectSource. The function can be "in-line" such as in this example:


To find out what engines are available and what sources they provide, run
<syntaxhighlight lang="javascript">dataEngine("time").connectSource("Local", function(source, data) { print(source); } )</syntaxhighlight>
<code>
 
plasmaengineexplorer
or reference a function elsewhere in the script as seen here:
</code>


You can choose from any of the installed data engines and request a source, including setting an update interval.  Just remember that when you are reading the data in QtScript, spaces in the keys provided by the sources are replaced by underscores.  So each source in the <tt>time</tt> engine provides a "Timezone Continent" key, but in QtScript you would access that as <tt>data.Timezone_Continent</tt> or <tt>data["Timezone_Continent"]</tt>.


<syntaxhighlight lang="javascript">function printSourceName(source, data) { print(source); }


== Testing it ==
dataEngine("time").connectSource("Local", printSourceName)</syntaxhighlight>


If you have KDE 4.3 or later, you can now test your plasmoid without installing it by running
== Disconnecting Engines ==
<code>
plasmoidviewer /path/to/plasmoid
</code>


Note that with KDE 4.2, you will have to install the plasmoid first with:
To disconnect a source, use the disconnectSource function from a DataEngine object. disconnectSource is symmetrical to connectSource and takes the name of the source and the target. The only difference is that disconnectSource does not take an optional time parameter as connectSource does.
<code>
plasmapkg -i /path/to/plasmoid
</code>
After that, you can run plasmoidviewer with the name of the plasmoid given by X-KDE-PluginInfo-Name in metadata.desktop. In this case:
<code>
plasmoidviewer yet-another-clock
</code>


<syntaxhighlight lang="javascript">dataEngine("time").disconnectSource("Local", plasmoid);</syntaxhighlight>


== Installing ==
== Pro tip: plasmaengineexplorer ==


Run the following command from the directory that contains <tt>metadata.desktop</tt>:
To find out what engines are available and what sources they provide, run
<code>
<syntaxhighlight lang="bash">
plasmapkg -i .
plasmaengineexplorer
</code>
</syntaxhighlight>


Now you can add it to your desktopFor packaging instructions, see [[Development/Tutorials/Plasma/QtScript/GettingStarted#Packaging|the getting started tutorial]].
You can choose from any of the installed data engines and request a source, including setting an update intervalJust remember that when you are reading the data in JavaScript, spaces in the keys provided by the sources are replaced by underscores.  So each source in the <tt>time</tt> engine provides a "Timezone Continent" key, but in JavaScript you would access that as <tt>data.Timezone_Continent</tt> or <tt>data["Timezone_Continent"]</tt>.

Latest revision as of 23:27, 11 September 2014

Getting Data

Abstract

Now that you've seen how to create a JavaScript plasmoid, we're going to move on to getting data into it.

Plasma has a data abstraction mechanism called DataEngines. You can ask for a DataEngine by name, request a source from it (again, by name) and you get data back from it, either at fixed intervals or whenever it is updated by the DataEngine internally. The data is a map (which is the same as an object in JavaScript) of string keys to data.

In this example, we'll get the local time from the time engine.

Connecting Engines to plasmoid.dataUpdated

Our contents/code/main.js will have the following content:

layout = new LinearLayout(plasmoid);

label = new Label();
layout.addItem(label);

plasmoid.dataUpdated = function(name, data) {
	label.text = data.Time;
}

dataEngine("time").connectSource("Local", plasmoid, 500);

There are two new things in this plasmoid. We've implemented plasmoid.dataUpdated, and connected a data engine source to it.

If you connect a data engine source to object, when there is an update for that source the method object.dataUpdated is called with two arguments: the name of the source and a map containing the data provided by the source.

In this case, plasmoid.dataUpdated gets called with "Local" as the first argument and the following object as the second argument (on my machine right now):

{
    Timezone_Continent: 'Europe',
    Offset: 3600,
    Timezone: 'Europe/London',
    Time: new Date('Sun May 17 20:06:20 2009 GMT+0100'),
    Timezone_City: 'Guernsey'
}

The last line of the script does the actual connection. We select the "time" data engine and request the "Local" source from it, which provide the local time. We tell it to connect to the plasmoid object and force an update every 500ms (every half a second).

If we left off the last parameter to connectSource (ie: didn't provide an update interval), then the source would be updated when there was new data available. This doesn't make much sense for a clock, where the time is continually changing, so would actually get no updates at all if you did this. However, there are other data engines (such as the "soliddevice" engine) where you only want to be notified when something changed, and in this case you would leave off the update interval.

Connecting Engines to Plasma Interface Elements

A number of Plasma interface elements support connecting DataEngines directly to them. These include:

  • Label
  • Meter
  • TextEdit

With these widgets, one can simply direct the DataEngine to update the widget directly and it will attempt to display the data. So in our example we could also write it as:


layout = new LinearLayout(plasmoid);

label = new Label();
layout.addItem(label);

dataEngine("time").connectSource("Local", label, 500);

While this is not as flexible as implementing plasmoid.dataUpdated, it can be a useful technique.

Connecting Engines to Arbitrary Functions

It is also possible to connect DataEngines to any Javascript function by passing it in as an argument to connectSource. The function can be "in-line" such as in this example:

dataEngine("time").connectSource("Local", function(source, data) { print(source); } )

or reference a function elsewhere in the script as seen here:


function printSourceName(source, data) { print(source); } 

dataEngine("time").connectSource("Local", printSourceName)

Disconnecting Engines

To disconnect a source, use the disconnectSource function from a DataEngine object. disconnectSource is symmetrical to connectSource and takes the name of the source and the target. The only difference is that disconnectSource does not take an optional time parameter as connectSource does.

dataEngine("time").disconnectSource("Local", plasmoid);

Pro tip: plasmaengineexplorer

To find out what engines are available and what sources they provide, run

plasmaengineexplorer

You can choose from any of the installed data engines and request a source, including setting an update interval. Just remember that when you are reading the data in JavaScript, spaces in the keys provided by the sources are replaced by underscores. So each source in the time engine provides a "Timezone Continent" key, but in JavaScript you would access that as data.Timezone_Continent or data["Timezone_Continent"].