Tabbles Plugin development and API documentation

From Tabbles Wiki
Revision as of 09:18, 21 September 2017 by Andrea (talk | contribs) (Created page with "== Currently outdate (01.09.2017) == This article is currently outdated as it refers to Tabbles 2.4. We're working to update it :) Until then, have a look at our [Github pag...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Currently outdate (01.09.2017)

This article is currently outdated as it refers to Tabbles 2.4. We're working to update it :) Until then, have a look at our [Github page https://github.com/tabbles].

Overview

A Tabbles plugin is a dll which is loaded at runtime by Tabbles and then runs in the same process as the Tabbles executable. Due to being in the same process, a plugin gains read and write access to the tabbles database (which is entirely in RAM), and there are no limitations to the changes it can do to the database.

Events. After a plugin is loaded by Tabbles, it gets notified of certain events (like “a file was just tagged by the user with these tabbles”, etc.). The plugin can then react to these events in any way. A plugin is also free to show its own window, or to start its own thread which will be running in the background.

Sample code

Refer to to our Tabbles Plugin Directory Scan source code on github

Creating a plugin

To create a Tabbles plugin, you have to create a .NET “class library” project which depends on the .NET framework 4.0. [insert video]. and then you have to add references to TabblesApi.dll, Tabbles_decl.dll and Tabbles_logic.dll. These dlls can be found in the same folder where Tabbles.exe is located, after installing Tabbles (e.g. C:\Program Files\Yellow blue soft\Tabbles).

The main class of the plugin must implement the IPlugin interface, otherwise Tabbles will not recognize it as a plugin.

Tutorial: Tabbles plugin development

We are now going to develop a basic Tabbles plugin which scans a directory chosen by the user and sends messages of the kind “tag file X with tabble Y” to Tabbles. The communication is unidirectional, i.e. the plugin does not receive messages from Tabbles.

  • In Visual Studio 2010, create a project of type “WPF user control library”. Call it tabblesPluginDirectoryScan. As the target .NET framework, choose 4.0.
  • Make sure Tabbles 2.4.10 or above is installed. It may or may not be running.
  • In Solution Explorer, right click the project, and choose “add reference...”. Browse to c:\program files\yellow blue soft\tabbles, and select the following dlls:

tabbles_logic.dll,

tabbles_decl.dll,

WpfcontrolLibrary1.dll,

TabblesApi.dll.

  • Also add a reference to Fsharp.Core.dll versione 4.0.0.0. This is supplied with Visual Studio 2010
  • right-click the project, click add -> class, and create a new file called plugin.cs. A class called plugin will be created in it.
  • In the plugin class, implement the following interfaces (defined in TabblesApi.dll):

public class plugin : TabblesApi.IPlugin, TabblesApi.IInitializable, TabblesApi.IMainMenuExtender

  • Implement all the basic methods such as the following:
  public string Name
       {
           get
           {
               return "Directory Scan";
           }
       }

These methods are self-explanatory. See the source code for more details.

  • Leave the implementation of IMainMenuExtender.menuItems() empty for now.

Note: we are not implementing TabblesApi.IEventListener because in this case our plugin must not be notified of events from Tabbles (such as “the user tagged file X with tabble Y”), but it must only send messages to Tabbles (such as “tag file X with tabble Y”). Add a WPF window to the project, and call it MainWindow.xaml. Add to it an empty textbox, which will contain the path of the directory to be scanned, and a Button with the text “scan”.

Now we could build the plugin project and then manually copy the output dll in the Documents/Tabbles/Plugins folder. But this should be done each time we rebuild the plugin. To avoid this, in the plugin project set as output folder the Documents/Tabbles/Plugins folder: Right-click the project; click “properties”; click the “build” tab; locate the “output path” section; click “browse”; select the Documents/Tabbles/Plugins folder (create the Plugin folder it if it does not exist).

  • Now build the project.
  • Enter Documents/Tabbles/Plugins and notice Visual studio put a lot of files in it, including a lot of dlls. Delete all those files except the project dll, tabblesPluginDirectoryScan.dll. (If you keep those files, Tabbles will crash at startup).
  • Restart Tabbles.
  • Open a Tabbles window.

To verify that the plugin was successfully loaded by Tabbles, open the Tabbles log via menu or by pressing CTRL+SHIFT+D. In the log window, look for a line like: Plugin object created: tabblesPluginDirectoryScan.plugin from file C:\Users\xxx\Documents\Tabbles\Plugins\tabblesPluginDirectoryScan.dll this means the plugin was successfully loaded by Tabbles. At this time, the plugin still does not do anything. Now we want to modify it so that it adds a menu item in Tabbles’ “plugins” menu. When the menu item is clicked, we want the plugin main window to show up. We can obtain this result by implementing the IMainMenuExtender.menuItems() method, in the plugin.cs file:

 
 public IEnumerable<TabblesApi.MenuItem> menuItems()
       {
           var l = new List<TabblesApi.MenuItem>();
           var mi = new TabblesApi.MenuItem
           {
               Name = "Show",
               Tooltip = "Show the plugin window",
               // when the menu item is clicked...
               onItemClicked = () =>
               {
                   //... show the plugin main window. This must be done 
                   // in the gui thread as WPF is not multithreaded.
                   TabblesApi.API.ExecuteActionInGuiThread(() =>
                   {
                       var wi = new MainWindow();
                       wi.Show();
                   });
               }
           };
           l.Add(mi);
           return l;

       }

Note: the code above wraps the call to wi.Show() into a call to TabblesApi.API.ExecuteActionInGuiThread(() => {...}); As a rule, any code that uses WPF calls must be wrapped in that function. The reason is that WPF is not thread-safe, so any code that uses WPF must run in Tabbles’ main thread (also called UI thread). The above call is how you force some code to run in Tabbles’ main thread. Let us rebuild the project and restart Tabbles. Now, in Tabbles’ plugins menu, we can see the menu item for our plugin “Directory Scan”. Click it and the plugin window should appear.

Now we have to write the logic for the “scan” button in the plugin window. You can find this logic, well commented, in the MainWindow.xaml.cs file, btnScan_Click() method.

In pseudocode, the logic is as follows:

  • for each file F in the given folder, recursively:
  • take the file name of F without the extension;
  • split the flie name using “_” and “-” as separators, obtaining several pieces;
  • skip the first piece;
  • for each remaining piece P:
  • create a tabble called P, if it does not already exist;
  • put file F in tabble P.

Functions

Note: the functions of tabbles-core illustrated in the code are:

db.formulaExists

db.dbCreateTabble2

db.tagCtsNonRecursive

plus the following secondary functions:

myLog.printDisp

db.getFirstColor()