Liblicense tutorial
Contents
Python and GTK
With the release of liblicense (ll) 0.3 we've introduced the beginnings of desktop integration. With this brief guide I hope to drive further integration into other apps. While I'll be using the python bindings for simplicity, the C bindings are very similar. In this section I will show how the integration through nautilus-python is done. Here is a screenshot from nautilus.
The first step of writing any plugin is figuring out the relevant APIs. In this case, the relevant APIs are that of liblicense and nautilus-python. The former's API is familiar to me because I wrote it but for consistencies sake the documentation is on the wiki. The nautilus-python documentation is pretty sparse as is the nautilus extension C documentation. However, I found this documentation file on the gnome svn. There are two primary integrations which I'll talk about. The first is the license emblem shown in the screenshot above. The second is a license properties tab. We'll start with the emblem because it uses the read function of liblicense.
First off to have nautilus load the plugin we place the python file in either /usr/lib/nautilus/extensions-1.0/python or ~/.nautilus/python-extensions/. Our name for the file is nautilus-liblicense.py. We'll put both aspects of the integration in this file. Next we'll import the necessary modules.
import liblicense import urllib import gtk import nautilus from liblicense.gui_gtk import *
Urllib is used to replace things such as %20 (for space) with their correct character. Gtk can be ignored for now as we'll see it in the second part. The nautilus import provides the classes which we'll subclass to provide the desired functionality. Lastly, the two liblicense imports provide us with the library functions and the gtk selector widget which we'll use later.
In order to process the files upon load we'll subclass the InfoProvider class from nautilus-python (imported as nautilus). Within this class we need to override one function, update_file_info, which takes on argument, a FileInfo object, in addition to self.
The class so far:
class LicenseInfoProvider(nautilus.InfoProvider): def __init__(self): pass def update_file_info(self, f): pass
There is nothing we need to do upon init but we'll leave it there. In a nautilus-python example they did similar. So now in the update_file_info function we'll need to read the license of the file and assign a corresponding emblem. Currently, two emblems are used, one for Creative Commons licenses and another for anything else. Here is this final code of the update_file_info function.
def update_file_info(self, f): if f.get_uri()[:7]=="file://": license = liblicense.read(urllib.unquote(f.get_uri()[7:])) if license: if "Creative Commons" in liblicense.get_attribute(license,"http://purl.org/dc/elements/1.1/creator",False): f.add_emblem("cc") else: f.add_emblem("licensed")
The first check that is done makes sure that the argument is a local file by check that it begins with "file://". Once that is confirmed, we then read the license of the file by calling liblicense.read(filename). Here urllib is used to convert url encoded characters, such as %20 for a space, so that we have an accurate file path. This is all done on everything after the first seven characters of the uri which get_uri() returned.
After the license is read we check that it is not null. If its not then we use liblicense.get_attribute to get the creator of the license to check if it is Creative Commons or not. We use python's keyword in because get_attribute returns a list of values. The arguments for get_attribute are the license uri, the desired attributes uri (the predicate in RDF terms) and finally a boolean toggling the locale awareness of the processing. Once all of this is done we add the corresponding emblem using the FileInfo object's add_emblem function which takes the emblem keyword. Upon install of liblicense these two icons are added. The keyword is taken from the filename (emblem-keyword.{png,svg}) not the .icon file. That explains all of the first part. If you have further questions visit #cc on irc.freenode.net or email cc-devel@lists.ibiblio.org.
Command-line Interface
License Chooser
Liblicense aims to make integration of license selection into applications seamless. The license chooser API allows for selecting licenses based on what the license permits, requires, and/or prohibits. For example, the license chooser API makes an excellent backend to the following:
C bindings
#include <liblicense.h> #include <stdio.h> int main() { ll_init(); char *attributes[] = { "http://creativecommons.org/ns#Distribution", "http://creativecommons.org/ns#CommercialUse", "http://creativecommons.org/ns#DerivativeWorks", "http://creativecommons.org/ns#ShareAlike", "http://creativecommons.org/ns#Attribution", NULL }; ll_license_chooser_t *chooser = ll_new_license_chooser(NULL,attributes); int permits, requires, prohibits; //permits Distribution(0) and DerivativeWorks(2) permits = (1 << 0) | (1 << 2); //requires ShareAlike(3) and Attribution(4) requires = (1 << 3) | (1 << 4); //prohibits CommericalUse(1) prohibits = (1 << 1); const ll_license_list_t *licenses = ll_get_licenses_from_flags(chooser,permits,requires,prohibits); while (licenses) { printf("%s\n",licenses->license); licenses = licenses->next; } ll_free_license_chooser(chooser); ll_stop(); return 0; }
Note how flags are specified. For example, if we want a license that requires Attribution, we need to set the 4th bit of "requires". This is because Attribution is the 4th element in the attribute array (remember, zero-based indexes here).
Python bindings
Python bindings greatly simplify the above. This retrieves all licenses that permit Distribution and Derivative Works and don't require Attribution or Notice (in other words, Public Domain).
from liblicense import LicenseChooser attributes = ["http://creativecommons.org/ns#Distribution", "http://creativecommons.org/ns#DerivativeWorks", "http://creativecommons.org/ns#Attribution", "http://creativecommons.org/ns#Notice"] chooser = LicenseChooser(None,attributes) print chooser.get_licenses(permits=(1 << 0) | (1 << 1))
See the C bindings example for more details.