Writing Kate Plugins

Introduction

First at all, why writing plugins for an editor ? Good question, and I hope I have a good answer: Because we want the base app be small and all extended features not all users need should go into plugins (like CVS suppport, project managment, coffee cooking ;) Therefore Kate provides a quite fullfeatured plugin interface and interfaces to all important stuff in the kate application (the documents, views, mainwindows, sidebar ...).

This tutorial is for people knowing the Qt/KDE libs (and how to code regular KDE apps) and will not describe how to compile, make ... a kde/qt program/lib in detail.

The "helloworld" plugin which is here described can be found in the "kdeaddons" package of kde (located in kdeaddons/kate/helloworld). A detailed description of the Kate API is available here..

Coding example: A little Hello World plugin ;)

Like in each programming language learning book I start with an easy "Hello World!" plugin, too ;) This plugin only implements a menuitem and inserts the string "Hello World!" into the current document. The example should show only the basic stuff you need to get your first plugin running, extensions won't be too hard because some existing plugins in kdeaddons are available to steal some code and the API is quiet self-explaining (I hope ;)

Needed files for a plugin

Each plugin consists of at least 3 files which are needed:

  • a desktop file with some information about the plugin (correct syntax described later - named like kate"pluginname".desktop
  • a xmlGUI rc file named ui.rc
  • a lib containing the plugin (named like kate"pluginname"plugin)

About the desktop file

The desktop file needs the syntax shown here and must be located in kde services directory with the name kate"yourpluginname".desktop,

Example: katehelloworld.desktop

[Desktop Entry]
Type=Service
ServiceTypes=Kate/Plugin
X-KDE-Library=katehelloworldplugin
X-Kate-Version=2.5
Name=My first Kate Plugin
Comment=Your short description about the plugin goes here

To get your file to kde services dir, for example in kde cvs the entry:

kde_services_DATA = katehelloworld.desktop

in your Makefile.am will do the trick, or manually copy it to $(kdedir)/share/services

The "X-Kate-Version=2.5" line is important! Kate 2.2 and up won't load your plugin unless the property is similar to the version with which you want to use the plugin!

About the xmlGUI rc file

The xmlGUI file must be named ui.rc and installed into $(kde_datadir)/kate/plugins/kate"yourpluginname". The content is free (should describe your needed menuitems + button for the plugin GUI ;)

Example: ui.rc for katehelloworldplugin

<!DOCTYPE kpartgui>
<kpartplugin name="katehelloworld" library="libkatehelloworldplugin" version="1">
<MenuBar>
 <Menu name="edit"><Text>&Edit</Text>
    <Action name="edit_insert_helloworld" />
 </Menu>
</MenuBar>
</kpartplugin>

About plugin lib

Each kate plugin is a lib which will be dynamically loaded by kate via KLibLoader. The name of the lib must be kate"yourpluginname"plugin.la and should be installed into the kde module dir.

Short example out of helloworld plugin Makefile.am

# Install this plugin in the KDE modules directory
kde_module_LTLIBRARIES = katehelloworldplugin.la

katehelloworldplugin_la_SOURCES = plugin_katehelloworld.cpp
katehelloworldplugin_la_LIBADD = -lkateinterfaces
katehelloworldplugin_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)

Start the real coding ;)

Now we can start with the real coding, The Hello World! plugin consists of 2 files, plugin_katehelloworld.cpp and .h.

The plugin header file - plugin_katehelloworld.h

#ifndef _PLUGIN_KATE_HELLOWORLD_H_
#define _PLUGIN_KATE_HELLOWORLD_H_

#include <kate/application.h>
#include <kate/documentmanager.h>
#include <kate/document.h>
#include <kate/mainwindow.h>
#include <kate/plugin.h>
#include <kate/view.h>
#include <kate/viewmanager.h>

#include <klibloader.h>
#include <klocale.h>

class KatePluginFactory : public KLibFactory
{
  Q_OBJECT

  public:
    KatePluginFactory();
    virtual ~KatePluginFactory();

    virtual QObject* createObject( QObject* parent = 0, 
                                   const char* pname = 0,
                                   const char* name = "QObject",
                                   const QStringList &args = QStringList() );

  private:
    static KInstance* s_instance;
};

class KatePluginHelloWorld : public Kate::Plugin, Kate::PluginViewInterface
{
  Q_OBJECT

  public:
    KatePluginHelloWorld( QObject* parent = 0, const char* name = 0 );
    virtual ~KatePluginHelloWorld();

    void addView (Kate::MainWindow *win);
    void removeView (Kate::MainWindow *win);

  public slots:
    void slotInsertHello();

  private:
    QPtrList<class PluginView> m_views;
};

#endif

The plugin header file - line by line

#ifndef _PLUGIN_KATE_HELLOWORLD_H_
#define _PLUGIN_KATE_HELLOWORLD_H_

Avoids the file to be included more than once.

#include <kate/application.h>
#include <kate/docmanager.h>
#include <kate/document.h>
#include <kate/mainwindow.h>
#include <kate/plugin.h>
#include <kate/view.h>
#include <kate/viewmanager.h>

#include <klibloader.h>
#include <klocale.h>

Includes the Kate Plugin Interface headers and some other needed kde headers.

class KatePluginFactory : public KLibFactory
{
  Q_OBJECT

  public:
    KatePluginFactory();
    virtual ~KatePluginFactory();

    virtual QObject* createObject( QObject* parent = 0,
                                   const char* pname = 0,
                                   const char* name = "QObject",
                                   const QStringList &args = QStringList() );

  private:
    static KInstance* s_instance;
};

Standard factory, is the same in each Kate plugin, is needed to load the plugin nicely via KLibLoader.

class KatePluginHelloWorld : public Kate::Plugin, Kate::PluginViewInterface
{
  Q_OBJECT

  public:
    KatePluginHelloWorld( QObject* parent = 0, const char* name = 0 );
    virtual ~KatePluginHelloWorld();

    void addView (Kate::MainWindow *win);
    void removeView (Kate::MainWindow *win);
};

This methode create the GUI (via xmlGUI) of the plugin for each Kate MainWindow. (if you open a new
mainwindow in kate, addView will be called, if a main win will be destroyed, removeView will be called)

  public slots:
    void slotInsertHello();

  private:
    QPtrList<class PluginView> m_views;
};
#endif

KatePluginHelloWorld is the real plugin class in the file. derivered from Kate::Plugin.

The plugin source file - plugin_katehelloworld.cpp

#include "plugin_katehelloworld.h"
#include "plugin_katehelloworld.moc"

#include <kaction.h>
#include <klocale.h>
#include <kstandarddirs.h>

class PluginView : public KXMLGUIClient
{
  friend class KatePluginHelloWorld;

  public:
    Kate::MainWindow *win;
};

extern "C"
{
  void* init_katehelloworldplugin()
  {
    KGlobal::locale()->insertCatalogue("katehelloworld");
    return new KatePluginFactory;
  }
}

KatePluginFactory::KatePluginFactory()
{
  s_instance = new KInstance( "kate" );
}

KatePluginFactory::~KatePluginFactory()
{
  delete s_instance;
}

QObject* KatePluginFactory::createObject( QObject* parent,
                                          const char* name,
                                          const char*,
                                          const QStringList & )
{
  return new KatePluginHelloWorld( parent, name );
}

KInstance* KatePluginFactory::s_instance = 0L;

KatePluginHelloWorld::KatePluginHelloWorld( QObject* parent, const char* name )
    : Kate::Plugin ( (Kate::Application*)parent, name )
{
}

KatePluginHelloWorld::~KatePluginHelloWorld()
{
}

void KatePluginHelloWorld::addView(Kate::MainWindow *win)
{
    // TODO: doesn't this have to be deleted?
    PluginView *view = new PluginView ();

     (void) new KAction ( i18n("Insert Hello World"), 0, this,
                          SLOT( slotInsertHello() ),
                          view->actionCollection(),
                          "edit_insert_helloworld" );

    view->setInstance (new KInstance("kate"));
    view->setXMLFile("plugins/katehelloworld/ui.rc");
    win->guiFactory()->addClient (view);
    view->win = win;

   m_views.append (view);
}

void KatePluginHelloWorld::removeView(Kate::MainWindow *win)
{
  for (uint z=0; z < m_views.count(); z++)
    if (m_views.at(z)->win == win)
    {
      PluginView *view = m_views.at(z);
      m_views.remove (view);
      win->guiFactory()->removeClient (view);
      delete view;
    }
}

void KatePluginHelloWorld::slotInsertHello()
{
  Kate::View *kv = application()->activeMainWindow()->viewManager()->activeView();

  if (kv)
    kv->insertText ("Hello World");
}

The plugin source file - line by line

#include "plugin_katehelloworld.h"
#include "plugin_katehelloworld.moc"

#include <kaction.h>
#include <klocale.h>
#include <kstddirs.h>

Include the header + moc file of the plugin + some kde includes needed by the plugin.

extern "C"
{
  void* init_libkatehelloworldplugin()
  {
    return new KatePluginFactory;
  }
}

Allow to load the lib via factory, init_libkatehelloworldplugin() must be renamed to init_libkate"yourpluginname"plugin() if you write your own plugin, it must match libname.

KatePluginFactory::KatePluginFactory()
{
  s_instance = new KInstance( "kate" );
}

KatePluginFactory::~KatePluginFactory()
{
  delete s_instance;
}

QObject* KatePluginFactory::createObject( QObject* parent,
                                          const char* name, const char*,
                                          const QStringList & )
{
  return new KatePluginHelloWorld( parent, name );
}

KInstance* KatePluginFactory::s_instance = 0L;

Some factory stuff, same in each plugin, only the createObject methode must call the constructor of your plugin class.

KatePluginHelloWorld::KatePluginHelloWorld( QObject* parent,
       const char* name )
    : Kate::Plugin ( parent, name )
{
}

KatePluginHelloWorld::~KatePluginHelloWorld()
{
}

Constructor/Destructor of our example plugin class, nothing to do for us, only pass the arguments to Kate::Plugin.

void KatePluginHelloWorld::addView(Kate::MainWindow *win)
{
    // TODO: doesn't this have to be deleted?
    PluginView *view = new PluginView ();

     (void) new KAction ( i18n("Insert Hello World"), 0, this,
                      SLOT( slotInsertHello() ), view->actionCollection(),
                      "edit_insert_helloworld" );

    view->setInstance (new KInstance("kate"));
    view->setXMLFile("plugins/katehelloworld/ui.rc");
    win->guiFactory()->addClient (view);
    view->win = win;

   m_views.append (view);
}

Here the GUI is created. The connected slot is part of the helloworld
plugin class.

void KatePluginHelloWorld::slotInsertHello()
{
  Kate::View *kv = application()->activeMainWindow()->viewManager()->activeView();

  if (kv)
    kv->insertText ("Hello World");
}

Here the actions takes place ;) This slot is called if you hit the "Insert Hello World" menuitem which is created by the pluginview.
application()->activeMainWindow()->viewManager()->activeView() gets the current active view of kate and kv->insertText("Hello World") inserts the text at the current cursor position. Done ;)

How does the Plugin look & work after install ?

You first have to go to the settings->plugins->manager configpage in Kate and activate the Hello World plugin, after that you have a "Insert Hello World" menuitem in your edit menu like on the screenshot. If you activate the menuitem the text "Hello World" will appear at the cursorposition in your current document.

More information ? Advanced plugin stuff ?

To get more information about the plugin interface and its advanced functions please look at the Kate API documentation or drop me a mail ;).
The complete sources (with Makefile.am) of this example can be found in kde cvs under kdeaddons/kate/helloworld or via webcvs here.

Comments

a plugin to write plugins

pate>http://paul.giannaros.org/pate/

How can I compile it with

How can I compile it with automake? How to compile this by directly invoking gcc (if automake is not installed)? Thank you very much for this information.

Nice Post

Thanks for this nice and informative post! seo services

Broken Link

Could you please fix the broken link. Thanks in advance Car Donation

Plugin to modify printed output?

I’d like to print from Kate, but have the printout highlight alternating lines of text so lines that wrap will be visually easier to see. Is that possible with the Kate plugins, or do I need to look to something else? (I’m using Kubuntu 7.10)

A Letter to Kate

Just as a sidenote you might be interested in this letter from a certain J. Appleseed. :-)

/Andreas

make

compiling is most difficult to newbies; more difficult than reading and understanding sources !!!!

how to compile

Makefile.am Should this be compiled with automake?

automake

automake: configure.ac' orconfigure.in’ is required

autoscan

autom4te: configure.ac: no such file or directory

??

How can I compile it with automake? How to compile this by directly invoking gcc (if automake is not installed)?

Broken links

The link to KDE API documentation and the link to the source are broken. Particularly, the source link should point to the SVN not CVS ;-)

Post new comment

  • You can use Markdown syntax to format and style the text.
  • You may link to images on this site using a special syntax
  • Web page addresses and e-mail addresses turn into links automatically.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Copy the characters (respecting upper/lower case) from the image.