Neverendingo (Talk | contribs) m (Text replace - "<code cppqt>" to "<syntaxhighlight lang="cpp-qt">") |
|||
| Line 73: | Line 73: | ||
=== The header file === | === The header file === | ||
'''timedate.h''' | '''timedate.h''' | ||
| − | < | + | <syntaxhighlight lang="cpp-qt"> |
// Avoid multiple header inclusion | // Avoid multiple header inclusion | ||
#ifndef TIMEDATE_H | #ifndef TIMEDATE_H | ||
| Line 168: | Line 168: | ||
=== The source file === | === The source file === | ||
'''timedate.cpp''' | '''timedate.cpp''' | ||
| − | < | + | <syntaxhighlight lang="cpp-qt"> |
// Own includes | // Own includes | ||
#include "timedate.h" | #include "timedate.h" | ||
| 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
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
// Avoid multiple header inclusion #ifndef TIMEDATE_H #define TIMEDATE_H // Include the basics #include <ktexteditor/plugin.h> #include <ktexteditor/view.h> #include <kxmlguiclient.h> #include <klocalizedstring.h> #include <QtCore/QEvent> #include <QtCore/QObject> #include <QtCore/QList> // This is the default string that will be printed out. As not everybody prints // it by default as: MM-DD-YYYY HH:MM, but for example, on other cultures we can // find DD-MM-YYYY HH:MM, we mark this default string for translators to translate // it. With this macro I18N_NOOP2 we are able to add comments for making the translation // easier and in context. If a translator sees "%m-%e-%Y %H:%M" can think: "what is this // guy talking about?". So we add the explanation on the first parameter. // Anyway, this is not important, do not get stucked here. If you do not understand // this declaration, think of it as: // // static QString localizedTimeDate = "%m-%e-%Y %H:%M"; static QString localizedTimeDate = I18N_NOOP2("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"); /** * 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 = 0, const QStringList &args = QStringList()); // 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(); virtual void readConfig (KConfig *) {} virtual void writeConfig (KConfig *) {} 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; }; #endif // TIMEDATE_H </code> === The source file === '''timedate.cpp''' <syntaxhighlight lang="cpp-qt"> // Own includes #include "timedate.h" // Include the basics #include <ktexteditor/document.h> #include <kgenericfactory.h> #include <klocale.h> #include <kaction.h> #include <kactioncollection.h> #include <kdatetime.h> // Without this macro call, the library loader won't find our plugin when trying // to load it. This macro adds code automagically that will let our plugin // be loaded on runtime. // The first parameter is the X-KDE-FactoryName on the .desktop file. // As we haven't provided such parameter, in this case (because our library is only // exporting one symbol, this plugin), we put here the X-KDE-LibraryName. // The second parameter will determine which type is our class, in this case it is // a TimeDatePlugin and the name of the X-KDE-FactoryName again. Same as before, // as we do not have X-KDE-FactoryName, we put there the X-KDE-LibraryName. // Is important to provide as last parameter "ktexteditor_plugins". K_EXPORT_COMPONENT_FACTORY(ktexteditor_timedate, KGenericFactory<TimeDatePlugin>("ktexteditor_timedate", "ktexteditor_plugins")) // Constructor TimeDatePlugin::TimeDatePlugin(QObject *parent, const QStringList &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(KGenericFactory<TimeDatePlugin>::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() { // 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. #include "timedate.moc" </code> === Building it all, the CMakeLists.txt === 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> # We are calling our plugin "ktexteditor_timedate", and it contains only # one source file: timedate.cpp. kde4_add_plugin(ktexteditor_timedate timedate.cpp) # We need to link our plugin against kdecore libs, as well as ktexteditor target_link_libraries(ktexteditor_timedate ${KDE4_KDECORE_LIBS} ktexteditor) # Well, we want to install our plugin on the plugin directory install(TARGETS ktexteditor_timedate DESTINATION ${PLUGIN_INSTALL_DIR}) # We also want to install the resource contents file on the data directory, at # the subdirectory of our plugin name, so it does not mix up with other resource # contents files. install(FILES timedateui.rc DESTINATION ${DATA_INSTALL_DIR}/ktexteditor_timedate) # We want to install the desktop file that describes our plugin too. It will go # on the services directory. install(FILES ktexteditor_timedate.desktop DESTINATION ${SERVICES_INSTALL_DIR}) </code> === The next part === 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.