Development/Tutorials/Using KParts: Difference between revisions
No edit summary |
|||
(28 intermediate revisions by 15 users not shown) | |||
Line 1: | Line 1: | ||
{{TutorialBrowser| | {{TutorialBrowser| | ||
Line 12: | Line 10: | ||
reading=[http://api.kde.org/4.x-api/kdelibs-apidocs/kparts/html/index.html KParts Documentation] | reading=[http://api.kde.org/4.x-api/kdelibs-apidocs/kparts/html/index.html KParts Documentation] | ||
}} | }} | ||
{{Review|Port to KF5}} | |||
Port to KF5 is WIP | |||
== Introduction == | == Introduction == | ||
Line 18: | Line 20: | ||
This tutorial will show you how to use a KPart in your application, and how to create your own KPart. | This tutorial will show you how to use a KPart in your application, and how to create your own KPart. | ||
KParts consist of a .desktop file describing the KPart and a .so file containing the function names and code. The .desktop file resides in KDE's services directory, you can find it out like this: | |||
#kf5-config --path services | |||
/home/username/.local/share/kservices5/:/usr/share/kservices5/ | |||
The first kPart we describe is KatePart, an editor representing a typical [http://api.kde.org/4.0-api/kdelibs-apidocs/kparts/html/classKParts_1_1ReadWritePart.html ReadWritePart]. A typical [http://api.kde.org/4.0-api/kdelibs-apidocs/kparts/html/classKParts_1_1ReadOnlyPart.html ReadOnlyPart] would be [http://api.kde.org/4.5-api/kdebase-apps-apidocs/konsole/html/classKonsole_1_1Part.html konsolePart]. | |||
== Using Katepart == | == Using Katepart == | ||
Line 27: | Line 35: | ||
=== main.cpp === | === main.cpp === | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
#include < | |||
#include <QApplication> | |||
#include <QUrl> | |||
#include <QCommandLineParser> | |||
#include <KAboutData> | #include <KAboutData> | ||
#include < | #include <KCrash> | ||
#include < | #include <KLocalizedString> | ||
#include "mainwindow.h" | #include "mainwindow.h" | ||
Line 37: | Line 50: | ||
int main (int argc, char *argv[]) | int main (int argc, char *argv[]) | ||
{ | { | ||
KAboutData aboutData( " | QApplication application(argc, argv); | ||
KLocalizedString::setApplicationDomain("amazeing"); | |||
KCrash::initialize(); | |||
KAboutData aboutData( QStringLiteral("kparttut1"), | |||
i18n("KPart Tutorial 1"), | |||
QStringLiteral("0.1"), | |||
i18n("A MainWindow for a KatePart."), | |||
KAboutLicense::GPL, | |||
i18n("Copyright (c) 2019 Developer") ); | |||
QCommandLineParser parser; | |||
aboutData.setupCommandLine(&parser); | |||
parser.process(application); | |||
aboutData.processCommandLine(&parser); | |||
const QStringList args = parser.positionalArguments(); | |||
MainWindow* window = new MainWindow(); | MainWindow* window = new MainWindow(); | ||
window->show(); | window->show(); | ||
if(!args.isEmpty()) | |||
if(args | |||
{ | { | ||
window->load(args | window->load(QUrl(args.first())); | ||
} | } | ||
Line 62: | Line 81: | ||
} | } | ||
</ | </syntaxhighlight> | ||
The main.cpp file is the same as that used in [[Development/Tutorials/KCmdLineArgs|Tutorial 5 - Command line arguments]].The only difference is in the details of the KAboutData. | The main.cpp file is the same as that used in [[Development/Tutorials/KCmdLineArgs|Tutorial 5 - Command line arguments]]. The only difference is in the details of the KAboutData. | ||
=== mainwindow.h === | === mainwindow.h === | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
#ifndef KPARTTUTORIAL1_H | #ifndef KPARTTUTORIAL1_H | ||
#define KPARTTUTORIAL1_H | #define KPARTTUTORIAL1_H | ||
#include < | #include <KParts/MainWindow> | ||
#include <QUrl> | |||
/** | |||
/** | |||
* This is the application "Shell". It has a menubar, toolbar, and | * This is the application "Shell". It has a menubar, toolbar, and | ||
* statusbar but relies on the "Part" to do all the real work. | * statusbar but relies on the "Part" to do all the real work. | ||
* | * | ||
* @short Application Shell | * @short Application Shell | ||
* @author Developer <[email protected]> | * @author Developer <[email protected]> | ||
* @version 0.1 | * @version 0.1 | ||
*/ | */ | ||
Line 95: | Line 115: | ||
* Default Destructor | * Default Destructor | ||
*/ | */ | ||
~MainWindow() override = default; | |||
public slots: | |||
/** | /** | ||
* Use this method to load whatever file/URL you have | * Use this method to load whatever file/URL you have | ||
*/ | */ | ||
void load(const | void load(const QUrl& url); | ||
/** | |||
* Use this method to display an openUrl dialog and | |||
* load the URL that gets entered | |||
*/ | |||
void load(); | |||
private: | private: | ||
Line 111: | Line 138: | ||
#endif // KPARTTUT1_H | #endif // KPARTTUT1_H | ||
</ | </syntaxhighlight> | ||
The mainwindow.h file is very simple. The important thing to notice here is that the MainWindow class inherits from KParts::MainWindow. | The mainwindow.h file is very simple. The important thing to notice here is that the MainWindow class inherits from KParts::MainWindow. | ||
Line 117: | Line 144: | ||
=== mainwindow.cpp === | === mainwindow.cpp === | ||
< | <syntaxhighlight lang="cpp-qt"> | ||
#include "mainwindow.h" | #include "mainwindow.h" | ||
#include < | #include <KActionCollection> | ||
#include < | #include <KConfig> | ||
#include < | #include <KEditToolBar> | ||
#include < | #include <KShortcutsDialog> | ||
#include < | #include <KMessageBox> | ||
#include < | #include <KService> | ||
#include < | #include <KStandardAction> | ||
#include < | #include <KParts/ReadWritePart> | ||
#include <QApplication> | #include <QApplication> | ||
#include <QFileDialog> | |||
#include <QStatusBar> | |||
MainWindow::MainWindow() | MainWindow::MainWindow() | ||
Line 142: | Line 168: | ||
setupActions(); | setupActions(); | ||
// | //query the .desktop file to load the requested Part | ||
KService::Ptr service = KService::serviceByDesktopName | |||
if ( | ("katepart"); | ||
if (service) { | |||
m_part = service->createInstance<KParts::ReadWritePart>(0); | |||
m_part = | |||
if (m_part) | if (m_part) { | ||
// tell the KParts::MainWindow that this is indeed | // tell the KParts::MainWindow that this is indeed | ||
// the main widget | // the main widget | ||
setCentralWidget(m_part->widget()); | setCentralWidget(m_part->widget()); | ||
setupGUI(ToolBar | Keys | StatusBar | Save); | |||
// and integrate the part's GUI with the shell's | // and integrate the part's GUI with the shell's | ||
createGUI(m_part); | createGUI(m_part); | ||
} else{ | |||
return;//return 1; | |||
} | } | ||
} else { | |||
} | |||
// if we couldn't find our Part, we exit since the Shell by | // if we couldn't find our Part, we exit since the Shell by | ||
// itself can't do anything useful | // itself can't do anything useful | ||
KMessageBox::error(this, " | KMessageBox::error(this, "service katepart not found"); | ||
qApp->quit(); | qApp->quit(); | ||
// we return here, cause qApp->quit() only means "exit the | // we return here, cause qApp->quit() only means "exit the | ||
Line 177: | Line 198: | ||
} | } | ||
MainWindow:: | void MainWindow::load(const QUrl& url) | ||
{ | { | ||
m_part->openUrl(url); | |||
m_part->openUrl( url ); | |||
} | } | ||
void MainWindow::setupActions() | void MainWindow::setupActions() | ||
{ | { | ||
KStandardAction::open(this, | KStandardAction::open(this, QOverload<>::of(&MainWindow::load), | ||
actionCollection()); | actionCollection()); | ||
KStandardAction::quit(qApp, | KStandardAction::quit(qApp, &QApplication::closeAllWindows, | ||
actionCollection()); | actionCollection()); | ||
} | } | ||
Line 196: | Line 213: | ||
void MainWindow::load() | void MainWindow::load() | ||
{ | { | ||
load( | load(QFileDialog::getOpenFileUrl()); | ||
} | } | ||
</ | </syntaxhighlight> | ||
The mainwindow.cpp file contains the implementation of MainWindow. The constructor of this class contains all the code used to load the KPart. | The mainwindow.cpp file contains the implementation of MainWindow. The constructor of this class contains all the code used to load the KPart. | ||
Line 207: | Line 224: | ||
=== kparttut1ui.rc === | === kparttut1ui.rc === | ||
< | <syntaxhighlight lang="xml"> | ||
<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> | <!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> | ||
<kpartgui name="kparttut1" version="1"> | <kpartgui name="kparttut1" version="1"> | ||
Line 226: | Line 243: | ||
</ToolBar> | </ToolBar> | ||
</kpartgui> | </kpartgui> | ||
</ | </syntaxhighlight> | ||
The kparttut1ui.rc file is used to define how the actions in the part and the actions in the main window will be merged together. The <tt><Merge /></tt> element in the file menu for example indicates that any part containing actions in a file menu should list its parts after the file_open action and before the file_quit action. | The kparttut1ui.rc file is used to define how the actions in the part and the actions in the main window will be merged together. The <tt><Merge /></tt> element in the file menu for example indicates that any part containing actions in a file menu should list its parts after the file_open action and before the file_quit action. | ||
Line 232: | Line 249: | ||
=== CMakeLists.txt === | === CMakeLists.txt === | ||
< | <syntaxhighlight lang="cmake"> | ||
cmake_minimum_required(VERSION 3.16) | |||
project(kparttut1) | project(kparttut1) | ||
set(QT_MIN_VERSION "5.15.0") | |||
set(KF_MIN_VERSION "5.82.0") | |||
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE) | |||
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) | |||
include(KDEInstallDirs) | |||
include(KDECMakeSettings) | |||
include(KDECompilerSettings NO_POLICY_SCOPE) | |||
include(ECMInstallIcons) | |||
include(FeatureSummary) | |||
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Core Gui Widgets) | |||
find_package(KF5 ${KF_MIN_VERSION} REQUIRED COMPONENTS | |||
CoreAddons | |||
Crash | |||
DBusAddons | |||
DocTools | |||
I18n | |||
XmlGui | |||
TextEditor | |||
Parts | |||
) | |||
set(kparttut1_SRCS | set(kparttut1_SRCS | ||
main.cpp | main.cpp | ||
mainwindow.cpp | mainwindow.cpp | ||
) | |||
add_executable(kparttut1 ${kparttut1_SRCS}) | |||
target_link_libraries(kparttut1 | target_link_libraries(kparttut1 PUBLIC | ||
Qt5::Widgets | |||
KF5::CoreAddons | |||
KF5::Crash | |||
KF5::DBusAddons | |||
KF5::DocTools | |||
KF5::I18n | |||
KF5::XmlGui | |||
KF5::TextEditor | |||
KF5::Parts | |||
) | |||
########### install files ############### | ########### install files ############### | ||
install(TARGETS kparttut1 | |||
install( FILES kparttut1ui.rc | install(TARGETS kparttut1 ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) | ||
DESTINATION ${ | |||
</ | install(FILES kparttut1ui.rc | ||
DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/kparttut) | |||
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) | |||
</syntaxhighlight> | |||
The CMakeLists.txt file is very simple in this case. | The CMakeLists.txt file is very simple in this case. | ||
== Running the Application == | == Running the Application == | ||
After compiling the application | After compiling, linking and installing the application with | ||
mkdir build && cd build && cmake .. && make -j4 && make install | |||
kparttut1 filename | it can be executed with | ||
kparttut1 ''filename'' | |||
where filename is a text file to load. One of the source files would be a good example. | where ''filename'' is a text file to load. One of the source files would be a good example. | ||
When the file loads you will have a full-featured kate editor running in its own window. All of the editor features of kate are available in the toolbars and menu. | When the file loads you will have a full-featured kate editor running in its own window. All of the editor features of kate are available in the toolbars and menu. | ||
Line 267: | Line 323: | ||
You will notice that the 'Open' action you defined in the MainWindow class has also appeared in the toolbar and in the menu along with the 'Quit' action. | You will notice that the 'Open' action you defined in the MainWindow class has also appeared in the toolbar and in the menu along with the 'Quit' action. | ||
The next tutorial will deal with creating your own | The next tutorial will deal with creating your own KParts for use (and reuse) in other applications. |
Latest revision as of 21:12, 12 August 2021
Tutorial Series | Plugins and KParts |
Previous | Tutorial 5 - Command line arguments |
What's Next | n/a |
Further Reading | KParts Documentation |
Parts to be reviewed:
Port to KF5Port to KF5 is WIP
Introduction
KPart technology is used in kde to reuse GUI components. The advantage that a KPart presents is that it comes with predefined toolbar actions. By using kparts in applications developers can spend less time implementing text editor or command line features, for example and just use a katepart or a konsolepart instead. KParts are also used with Plugin technology to embed applications inside another, such as integrating PIM applications into Kontact.
This tutorial will show you how to use a KPart in your application, and how to create your own KPart.
KParts consist of a .desktop file describing the KPart and a .so file containing the function names and code. The .desktop file resides in KDE's services directory, you can find it out like this:
#kf5-config --path services /home/username/.local/share/kservices5/:/usr/share/kservices5/
The first kPart we describe is KatePart, an editor representing a typical ReadWritePart. A typical ReadOnlyPart would be konsolePart.
Using Katepart
Simple KDE applications use a MainWindow derived from KMainWindow (such as in previous tutorials). To use a KPart in an application, the MainWindow must instead be derived from KParts::MainWindow. This will then take care of integrating the toolbar and menu items of the kpart together.
The following code creates a KParts::MainWindow with a kpart inside it.
main.cpp
#include <QApplication>
#include <QUrl>
#include <QCommandLineParser>
#include <KAboutData>
#include <KCrash>
#include <KLocalizedString>
#include "mainwindow.h"
int main (int argc, char *argv[])
{
QApplication application(argc, argv);
KLocalizedString::setApplicationDomain("amazeing");
KCrash::initialize();
KAboutData aboutData( QStringLiteral("kparttut1"),
i18n("KPart Tutorial 1"),
QStringLiteral("0.1"),
i18n("A MainWindow for a KatePart."),
KAboutLicense::GPL,
i18n("Copyright (c) 2019 Developer") );
QCommandLineParser parser;
aboutData.setupCommandLine(&parser);
parser.process(application);
aboutData.processCommandLine(&parser);
const QStringList args = parser.positionalArguments();
MainWindow* window = new MainWindow();
window->show();
if(!args.isEmpty())
{
window->load(QUrl(args.first()));
}
return app.exec();
}
The main.cpp file is the same as that used in Tutorial 5 - Command line arguments. The only difference is in the details of the KAboutData.
mainwindow.h
#ifndef KPARTTUTORIAL1_H
#define KPARTTUTORIAL1_H
#include <KParts/MainWindow>
#include <QUrl>
/**
* This is the application "Shell". It has a menubar, toolbar, and
* statusbar but relies on the "Part" to do all the real work.
*
* @short Application Shell
* @author Developer <[email protected]>
* @version 0.1
*/
class MainWindow : public KParts::MainWindow
{
Q_OBJECT
public:
/**
* Default Constructor
*/
MainWindow();
/**
* Default Destructor
*/
~MainWindow() override = default;
public slots:
/**
* Use this method to load whatever file/URL you have
*/
void load(const QUrl& url);
/**
* Use this method to display an openUrl dialog and
* load the URL that gets entered
*/
void load();
private:
void setupActions();
private:
KParts::ReadWritePart *m_part;
};
#endif // KPARTTUT1_H
The mainwindow.h file is very simple. The important thing to notice here is that the MainWindow class inherits from KParts::MainWindow.
mainwindow.cpp
#include "mainwindow.h"
#include <KActionCollection>
#include <KConfig>
#include <KEditToolBar>
#include <KShortcutsDialog>
#include <KMessageBox>
#include <KService>
#include <KStandardAction>
#include <KParts/ReadWritePart>
#include <QApplication>
#include <QFileDialog>
#include <QStatusBar>
MainWindow::MainWindow()
: KParts::MainWindow( )
{
// Setup our actions
setupActions();
//query the .desktop file to load the requested Part
KService::Ptr service = KService::serviceByDesktopName
("katepart");
if (service) {
m_part = service->createInstance<KParts::ReadWritePart>(0);
if (m_part) {
// tell the KParts::MainWindow that this is indeed
// the main widget
setCentralWidget(m_part->widget());
setupGUI(ToolBar | Keys | StatusBar | Save);
// and integrate the part's GUI with the shell's
createGUI(m_part);
} else{
return;//return 1;
}
} else {
// if we couldn't find our Part, we exit since the Shell by
// itself can't do anything useful
KMessageBox::error(this, "service katepart not found");
qApp->quit();
// we return here, cause qApp->quit() only means "exit the
// next time we enter the event loop...
return;
}
}
void MainWindow::load(const QUrl& url)
{
m_part->openUrl(url);
}
void MainWindow::setupActions()
{
KStandardAction::open(this, QOverload<>::of(&MainWindow::load),
actionCollection());
KStandardAction::quit(qApp, &QApplication::closeAllWindows,
actionCollection());
}
void MainWindow::load()
{
load(QFileDialog::getOpenFileUrl());
}
The mainwindow.cpp file contains the implementation of MainWindow. The constructor of this class contains all the code used to load the KPart.
First it sets up the actions used by the main window (Open and Quit), and then sets up the gui elements to go with these items (toolbar items, menu items, keyboard shortcuts). Next is the standard code used to load the KPart. The createGUI method is responsible for merging the toolbars and menus of the KPart with the rest of the application.
kparttut1ui.rc
<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
<kpartgui name="kparttut1" version="1">
<MenuBar>
<Menu noMerge="1" name="file"><text>&File</text>
<Action name="file_open"/>
<Separator/>
<Merge/>
<Separator/>
<Action name="file_quit"/>
</Menu>
<Merge />
</MenuBar>
<ToolBar noMerge="1" name="mainToolBar"><text>Main Toolbar</text>
<Action name="file_open"/>
<Merge/>
</ToolBar>
</kpartgui>
The kparttut1ui.rc file is used to define how the actions in the part and the actions in the main window will be merged together. The <Merge /> element in the file menu for example indicates that any part containing actions in a file menu should list its parts after the file_open action and before the file_quit action.
CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(kparttut1)
set(QT_MIN_VERSION "5.15.0")
set(KF_MIN_VERSION "5.82.0")
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(ECMInstallIcons)
include(FeatureSummary)
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Core Gui Widgets)
find_package(KF5 ${KF_MIN_VERSION} REQUIRED COMPONENTS
CoreAddons
Crash
DBusAddons
DocTools
I18n
XmlGui
TextEditor
Parts
)
set(kparttut1_SRCS
main.cpp
mainwindow.cpp
)
add_executable(kparttut1 ${kparttut1_SRCS})
target_link_libraries(kparttut1 PUBLIC
Qt5::Widgets
KF5::CoreAddons
KF5::Crash
KF5::DBusAddons
KF5::DocTools
KF5::I18n
KF5::XmlGui
KF5::TextEditor
KF5::Parts
)
########### install files ###############
install(TARGETS kparttut1 ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
install(FILES kparttut1ui.rc
DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/kparttut)
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
The CMakeLists.txt file is very simple in this case.
Running the Application
After compiling, linking and installing the application with
mkdir build && cd build && cmake .. && make -j4 && make install
it can be executed with
kparttut1 filename
where filename is a text file to load. One of the source files would be a good example.
When the file loads you will have a full-featured kate editor running in its own window. All of the editor features of kate are available in the toolbars and menu.
You will notice that the 'Open' action you defined in the MainWindow class has also appeared in the toolbar and in the menu along with the 'Quit' action.
The next tutorial will deal with creating your own KParts for use (and reuse) in other applications.