| Tutorial Series | Kate Plugin Tutorial |
| Previous | C++, Qt, KDE development environment |
| What's Next | Add a configuration dialog for it |
| Further Reading | CMake, The actual plugin code |
Contents |
We are going to create a dummy plugin for Kate in this tutorial. Our plugin will be able to insert current Date & Time. For now, our plugin will add on the cursor position on the active document the next information:
On the next chapter we will learn how to customize this output string creating a configuration dialog for this plugin.
Every plugin needs a .desktop file that describes it.
ktexteditor_timedate.desktop
[Desktop Entry]
Encoding=UTF-8
X-KDE-Library=ktexteditor_timedate
X-KDE-PluginInfo-Author=Konqui the Dragon
X-KDE-PluginInfo-Email=konqui@kde.org
X-KDE-PluginInfo-Name=ktexteditortimedate
X-KDE-PluginInfo-Version=0.1
X-KDE-PluginInfo-Website=http://kate.kde.org
X-KDE-PluginInfo-Category=Editor
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=false
X-KDE-ParentApp=kate
X-KDE-Version=4.0
ServiceTypes=KTextEditor/Plugin
Type=Service
Icon=korganizer
Name=Time & Date
Comment=Insert current Time & Date
</syntaxhighlight>
There are important parts on this file:
This file is the one that will let our plugin merge with the Kate environment (toolbars and/or menubars). In this case when our plugin is loaded this file tells the KDE XML classes that it will add a separator, and that there is an action named "tools_insert_timedate". We will need to interact with this action later.
timedateui.rc
<!DOCTYPE kpartgui> <kpartplugin name="ktexteditor_timedate" library="ktexteditor_timedate" version="2"> <MenuBar> <Menu name="tools"><Text>&Tools</Text> <separator group="tools_operations" /> <Action name="tools_insert_timedate" group="tools_operations"/> </Menu> </MenuBar> </kpartplugin>
timedate.h <code cppqt> // Avoid multiple header inclusion
// Include the basics
/**
* This is the plugin class. There will be only one instance of this class. * We always want to inherit KTextEditor::Plugin here. */
class TimeDatePlugin
: public KTextEditor::Plugin
{
public:
// Constructor
explicit TimeDatePlugin(QObject *parent,
const QVariantList &args);
// Destructor
virtual ~TimeDatePlugin();
// Overriden methods // This method is called when a plugin has to be added to a view. As there // is only one instance of this plugin, but it is possible for plugins to // behave in different ways in different opened views where it is loaded, in // Kate plugins are added to views. For that reason we have the plugin itself // (this class) and then the plugin view class. // In this methods we have to create/remove TimeDatePluginView classes. void addView (KTextEditor::View *view); void removeView (KTextEditor::View *view);
void readConfig(); void writeConfig();
private: QList<class TimeDatePluginView*> m_views;
};
/**
* This is the plugin view class. There can be as much instances as views exist. */
class TimeDatePluginView
: public QObject, public KXMLGUIClient
{
Q_OBJECT
public: explicit TimeDatePluginView(KTextEditor::View *view = 0); ~TimeDatePluginView();
private Q_SLOTS: void slotInsertTimeDate();
private: KTextEditor::View *m_view;
};
</syntaxhighlight>
timedate.cpp <code cppqt> // Own includes
// Include the basics
// This macro defines a KPluginFactory subclass named TimeDatePluginFactory. The second // argument to the macro is code that is inserted into the constructor of the class. // I our case all we need to do is register one plugin. If you want to have more // than one plugin in the same library then you can register multiple plugin classes // here. The registerPlugin function takes an optional QString parameter which is a // keyword to uniquely identify the plugin then (it maps to X-KDE-PluginKeyword in the // .desktop file). K_PLUGIN_FACTORY(TimeDatePluginFactory,
registerPlugin<TimeDatePlugin>();
)
// With the next macro call, the library exports version information about the // Qt and KDE libraries being used and (most important) the entry symbol to get at // the factory we defined above. // The argument this macro takes is the constructor call of the above factory which // provides two constructors. One which takes a KAboutData* and another one // that takes two (optional) const char* parameters (Same as for KComponentData // constructors). // We put there the X-KDE-LibraryName. // Is important to provide as last parameter "ktexteditor_plugins". K_EXPORT_PLUGIN(TimeDatePluginFactory("ktexteditor_timedate", "ktexteditor_plugins"))
// Constructor TimeDatePlugin::TimeDatePlugin(QObject *parent, const QVariantList &args)
: KTextEditor::Plugin(parent)
{
// Avoid warning on compile time because of unused argument Q_UNUSED(args);
}
// Destructor TimeDatePlugin::~TimeDatePlugin() { }
// Create the plugin view class and add it to the views list void TimeDatePlugin::addView(KTextEditor::View *view) {
TimeDatePluginView *nview = new TimeDatePluginView(view); m_views.append(nview);
}
// Find the view where we want to remove the plugin from, and remove it. // Do not forget to free the memory. void TimeDatePlugin::removeView(KTextEditor::View *view) {
for (int z = 0; z < m_views.size(); z++)
{
if (m_views.at(z)->parentClient() == view)
{
TimeDatePluginView *nview = m_views.at(z);
m_views.removeAll(nview);
delete nview;
}
}
}
// We do nothing on this methods since our plugin is not configurable yet void TimeDatePlugin::readConfig() { }
void TimeDatePlugin::writeConfig() { }
// Plugin view class TimeDatePluginView::TimeDatePluginView(KTextEditor::View *view)
: QObject(view) , KXMLGUIClient(view) , m_view(view)
{
setComponentData(TimeDatePluginFactory::componentData());
KAction *action = new KAction(i18n("Insert Time && Date"), this);
// Here we need as first parameter the same we declared at the resource
// contents file (timedateui.rc). We named the action "tools_insert_timedate".
// Here is where we connect it to an actual KDE action.
actionCollection()->addAction("tools_insert_timedate", action);
action->setShortcut(Qt::CTRL + Qt::Key_D);
// As usual, we connect the signal triggered() to a slot here. When the menu
// element is clicked, we go to the slot slotInsertTimeDate().
connect(action, SIGNAL(triggered()), this, SLOT(slotInsertTimeDate()));
// This is always needed, tell the KDE XML GUI client that we are using
// that file for reading actions from.
setXMLFile("timedateui.rc");
}
// Destructor TimeDatePluginView::~TimeDatePluginView() { }
// The slot that will be called when the menu element "Insert Time & Date" is // clicked. void TimeDatePluginView::slotInsertTimeDate() {
QString localizedTimeDate = i18nc("This is a localized string for default time & date printing on kate document."
"%e means day in XX format."
"%m means month in XX format."
"%Y means year in XXXX format."
"%H means hours in XX format."
"%M means minutes in XX format."
"Please, if in your language time or date is written in a different order, change it here",
"%m-%e-%Y %H:%M");
// We create a KDateTime object with the current time & date. KDateTime dt(QDateTime::currentDateTime()); // We insert the information in the document at the current cursor position // with the default string declared on the header. m_view->document()->insertText(m_view->cursorPosition(), dt.toString(localizedTimeDate));
}
// We need to include the moc file since we have declared slots and we are using // the Q_OBJECT macro on the TimeDatePluginView class.
</syntaxhighlight>
Finally, to put everything together you need to build everything, to tell cmake what needs to go where there is the CMakeLists.txt file.
For more details on CMake please read Development/Tutorials/CMake
<code bash> find_package(KDE4 REQUIRED) include (KDE4Defaults) include_directories(${KDE4_INCLUDES})
kde4_add_plugin(ktexteditor_timedate timedate.cpp)
target_link_libraries(ktexteditor_timedate ${KDE4_KDECORE_LIBS} ${KDE4_KDEUI_LIBS} ktexteditor)
install(TARGETS ktexteditor_timedate DESTINATION ${PLUGIN_INSTALL_DIR})
install(FILES timedateui.rc DESTINATION ${DATA_INSTALL_DIR}/ktexteditor_timedate)
install(FILES ktexteditor_timedate.desktop DESTINATION ${SERVICES_INSTALL_DIR}) </syntaxhighlight>
Now you are ready for adding to this plugin a configuration dialog that lets the user customize the way the string is printed out on the screen.