| Tutorial Series | Kate Plugin Tutorial |
| Previous | C++, Qt, KDE4 development environment |
| What's Next | Add a configuration dialog for it (Work in progress) |
| 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
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
static QString localizedTimeDate = QString();
class TimeDatePlugin
: public KTextEditor::Plugin
{
public:
explicit TimeDatePlugin(QObject *parent = 0,
const QVariantList &args = QVariantList());
virtual ~TimeDatePlugin();
static TimeDatePlugin *self() { return plugin; }
void addView (KTextEditor::View *view); void removeView (KTextEditor::View *view);
void readConfig(); void writeConfig();
virtual void readConfig (KConfig *) {}
virtual void writeConfig (KConfig *) {}
void setFormat(const QString &format); QString format() const;
private: static TimeDatePlugin *plugin; QList<class TimeDatePluginView*> m_views; QString m_string;
};
class TimeDatePluginView
: public QObject, public KXMLGUIClient
{
Q_OBJECT
public:
explicit TimeDatePluginView(const QString &string,
KTextEditor::View *view = 0);
~TimeDatePluginView();
void setFormat(const QString &format); QString format() const;
private Q_SLOTS: void slotInsertTimeDate();
private: KTextEditor::View *m_view; QString m_string;
};
K_PLUGIN_FACTORY_DECLARATION(TimeDatePluginFactory)
timedate.cpp
// 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)
{
// Insert the plugin view->insertChildClient(this); 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.
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
kde4_add_plugin(ktexteditor_timedate timedate.cpp)
target_link_libraries(ktexteditor_timedate ${KDE4_KDECORE_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})
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.