diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -3,8 +3,22 @@ include(ECMAddTests) +########### a KParts ############### + +set(notepadpart_SRCS notepad.cpp) +qt5_add_resources(notepadpart_SRCS notepad.qrc) +# don't use kcoreaddons_add_plugin here since we don't want to install it +add_library(notepadpart MODULE ${notepadpart_SRCS}) +# so we have to do the INSTALL_NAMESPACE thing by hand: +set_target_properties(notepadpart PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/kf5/parts") +kcoreaddons_desktop_to_json(notepadpart notepad.desktop) +target_link_libraries(notepadpart KF5::Parts) + +########### tests ############### + ecm_add_tests( parttest.cpp + partloadertest.cpp openorsavequestion_unittest.cpp LINK_LIBRARIES KF5::Parts Qt5::Test KF5::XmlGui ) diff --git a/tests/notepad.h b/autotests/notepad.h rename from tests/notepad.h rename to autotests/notepad.h --- a/tests/notepad.h +++ b/autotests/notepad.h @@ -22,8 +22,8 @@ #ifndef notepad_h #define notepad_h -#include #include +#include class KAboutData; class QTextEdit; @@ -57,4 +57,5 @@ QTextEdit *m_edit; }; + #endif diff --git a/tests/notepad.cpp b/autotests/notepad.cpp rename from tests/notepad.cpp rename to autotests/notepad.cpp --- a/tests/notepad.cpp +++ b/autotests/notepad.cpp @@ -27,15 +27,17 @@ #include #include #include -#include #include #include #include #include #include -K_PLUGIN_FACTORY(NotepadFactory, registerPlugin();) +K_PLUGIN_FACTORY_WITH_JSON(NotepadFactory, + "notepad.json", + registerPlugin(); + ) NotepadPart::NotepadPart(QWidget *parentWidget, QObject *parent, @@ -53,7 +55,7 @@ actionCollection()->addAction(QStringLiteral("searchreplace"), searchReplace); connect(searchReplace, SIGNAL(triggered()), this, SLOT(slotSearchReplace())); - setXMLFile(QFINDTESTDATA("notepadpart.rc")); + setXMLFile(QStringLiteral("notepadpart.rc")); // will be found in the qrc resource setReadWrite(true); @@ -106,7 +108,6 @@ return false; } QFile f(localFilePath()); - QString s; if (f.open(QIODevice::WriteOnly)) { QTextStream t(&f); t.setCodec("UTF-8"); diff --git a/autotests/notepad.qrc b/autotests/notepad.qrc new file mode 100644 --- /dev/null +++ b/autotests/notepad.qrc @@ -0,0 +1,7 @@ + + + + notepadpart.rc + + + diff --git a/tests/notepadpart.rc b/autotests/notepadpart.rc rename from tests/notepadpart.rc rename to autotests/notepadpart.rc diff --git a/autotests/partloadertest.cpp b/autotests/partloadertest.cpp new file mode 100644 --- /dev/null +++ b/autotests/partloadertest.cpp @@ -0,0 +1,109 @@ +/* + Copyright (c) 2020 David Faure + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License or ( at + your option ) version 3 or, at the discretion of KDE e.V. ( which shall + act as a proxy as in section 14 of the GPLv3 ), any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include + +#include +#include +#include + +class PartLoaderTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() + { + QStandardPaths::setTestModeEnabled(true); + + + const QString desktopFile = QFINDTESTDATA(QStringLiteral("notepad.desktop")); + QVERIFY(!desktopFile.isEmpty()); + QVERIFY(QFile::copy(desktopFile, QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kservices5/notepad.desktop"))); + // Ensure notepadpart is preferred over other installed parts. + // This also tests the mimeapps.list parsing in PartLoader + const QByteArray contents = "[Added KDE Service Associations]\n" + "text/plain=notepad.desktop;\n"; + const QString mimeAppsPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1String("/mimeapps.list"); + QFile mimeAppsFile(mimeAppsPath); + QVERIFY(mimeAppsFile.open(QIODevice::WriteOnly)); + mimeAppsFile.write(contents); + } + + void shouldListParts() + { + // GIVEN + const QString mimeType = QStringLiteral("text/plain"); + + // WHEN + const QVector plugins = KParts::PartLoader::partsForMimeType(mimeType); + + // THEN + QVERIFY(!plugins.isEmpty()); +// for (const KPluginMetaData &metaData : plugins) { +// qDebug() << metaData.fileName() << metaData.pluginId(); +// } + QCOMPARE(plugins.at(0).pluginId(), QStringLiteral("notepadpart")); // basename of plugin + const QString fileName = plugins.at(0).fileName(); + QVERIFY2(fileName.contains(QLatin1String("notepadpart")), qPrintable(fileName)); + } + + void shouldLoadPlainTextPart() + { + // GIVEN + const QString mimeType = QStringLiteral("text/plain"); + const QString testFile = QFINDTESTDATA("partloadertest.cpp"); + QVERIFY(!testFile.isEmpty()); + QWidget parentWidget; + QString errorString; + + // WHEN + KParts::ReadOnlyPart *part = KParts::PartLoader::createPartInstanceForMimeType(mimeType, + &parentWidget, this, &errorString); + + // THEN + QVERIFY(part); + QCOMPARE(errorString, QString()); + QCOMPARE(part->metaObject()->className(), "NotepadPart"); + QVERIFY(part->openUrl(QUrl::fromLocalFile(testFile))); + } + + void shouldHandleNoPartError() + { + // GIVEN + // can't use an unlikely mimetype here, okteta is associated with application/octet-stream :-) + const QString mimeType = QStringLiteral("does/not/exist"); + QWidget parentWidget; + QString errorString; + + // WHEN + KParts::ReadOnlyPart *part = KParts::PartLoader::createPartInstanceForMimeType(mimeType, + &parentWidget, this, &errorString); + + // THEN + QVERIFY2(!part, part ? part->metaObject()->className() : nullptr); + QCOMPARE(errorString, QStringLiteral("No part was found for mimeType does/not/exist")); + } +}; + +QTEST_MAIN(PartLoaderTest) + +#include "partloadertest.moc" diff --git a/src/partloader.h b/src/partloader.h --- a/src/partloader.h +++ b/src/partloader.h @@ -73,12 +73,15 @@ * * Example: * \code + * QString errorString; * m_part = KParts::PartLoader::createPartInstanceForMimeType( - * mimeType, this, this); + * mimeType, this, this, &errorString); * if (m_part) { * layout->addWidget(m_part->widget()); // Integrate the widget * createGUI(m_part); // Integrate the actions * m_part->openUrl(url); + * } else { + * qWarning() << errorString; * } * \endcode * diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,7 +6,6 @@ set(partstest_SRCS parts.cpp - notepad.cpp ) @@ -25,13 +24,6 @@ target_link_libraries(spellcheckplugin ${PARTS_TEST_LIBRARY_DEPENDENCIES} ) install(TARGETS spellcheckplugin DESTINATION ${KDE_INSTALL_PLUGINDIR} ) -########### next target ############### - -add_library(notepadpart MODULE notepad.cpp) -target_link_libraries(notepadpart ${PARTS_TEST_LIBRARY_DEPENDENCIES}) -install(TARGETS notepadpart DESTINATION ${KDE_INSTALL_PLUGINDIR} ) - - ########### unit tests ############### MACRO(KPARTS_EXECUTABLE_TESTS) diff --git a/tests/normalktm.cpp b/tests/normalktm.cpp --- a/tests/normalktm.cpp +++ b/tests/normalktm.cpp @@ -21,11 +21,13 @@ #include "normalktm.h" #include "parts.h" -#include "notepad.h" + +#include #include #include #include +#include #include #include #include @@ -111,12 +113,18 @@ // replace part2 with the editor part delete m_part2; m_part2 = nullptr; - m_editorpart = new NotepadPart(m_splitter, this); - m_editorpart->setReadWrite(); // read-write mode - ////// m_manager->addPart( m_editorpart ); - m_editorpart->widget()->show(); //// we need to do this in a normal KTM.... - m_paEditFile->setEnabled(false); - m_paCloseEditor->setEnabled(true); + QString errorString; + m_editorpart = KParts::PartLoader::createPartInstanceForMimeType( + QStringLiteral("text/plain"), m_splitter, this, &errorString); + if (!m_editorpart) { + qWarning() << errorString; + } else { + m_editorpart->setReadWrite(); // read-write mode + ////// m_manager->addPart( m_editorpart ); + m_editorpart->widget()->show(); //// we need to do this in a normal KTM.... + m_paEditFile->setEnabled(false); + m_paCloseEditor->setEnabled(true); + } } void TestMainWindow::slotFileCloseEditor() diff --git a/tests/partviewer.cpp b/tests/partviewer.cpp --- a/tests/partviewer.cpp +++ b/tests/partviewer.cpp @@ -61,18 +61,20 @@ delete m_part; QMimeDatabase db; const QString mimeType = db.mimeTypeForUrl(url).name(); + QString errorString; m_part = KParts::PartLoader::createPartInstanceForMimeType(mimeType, - this, this); + this, this, &errorString); if (m_part) { - qDebug() << "Loaded part" << m_part << "widget" << m_part->widget(); setCentralWidget(m_part->widget()); // Integrate its GUI createGUI(m_part); m_part->openUrl(url); + } else { + qWarning() << errorString; } } diff --git a/tests/plugin_spellcheck.cpp b/tests/plugin_spellcheck.cpp --- a/tests/plugin_spellcheck.cpp +++ b/tests/plugin_spellcheck.cpp @@ -20,7 +20,7 @@ #include "plugin_spellcheck.h" -#include "notepad.h" // this plugin applies to a notepad part +#include #include #include #include @@ -50,7 +50,7 @@ if (!parent()->inherits("NotepadPart")) { KMessageBox::error(nullptr, QStringLiteral("You just called the spell-check action on a wrong part (not NotepadPart)")); } else { - NotepadPart *part = (NotepadPart *) parent(); + KParts::ReadOnlyPart *part = static_cast(parent()); QTextEdit *widget = qobject_cast(part->widget()); Q_ASSERT(widget); widget->selectAll(); diff --git a/tests/testmainwindow.cpp b/tests/testmainwindow.cpp --- a/tests/testmainwindow.cpp +++ b/tests/testmainwindow.cpp @@ -21,7 +21,8 @@ #include "testmainwindow.h" #include "parts.h" -#include "notepad.h" + +#include #include #include @@ -123,11 +124,17 @@ // replace part2 with the editor part delete m_part2; m_part2 = nullptr; - m_editorpart = new NotepadPart(m_splitter, this); - m_editorpart->setReadWrite(); // read-write mode - m_manager->addPart(m_editorpart); - m_paEditFile->setEnabled(false); - m_paCloseEditor->setEnabled(true); + QString errorString; + m_editorpart = KParts::PartLoader::createPartInstanceForMimeType( + QStringLiteral("text/plain"), m_splitter, this, &errorString); + if (!m_editorpart) { + qWarning() << errorString; + } else { + m_editorpart->setReadWrite(); // read-write mode + m_manager->addPart(m_editorpart); + m_paEditFile->setEnabled(false); + m_paCloseEditor->setEnabled(true); + } } void TestMainWindow::slotFileCloseEditor() @@ -172,8 +179,6 @@ TestMainWindow *shell = new TestMainWindow; shell->show(); - app.exec(); - - return 0; + return app.exec(); }