Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package kf6-kcoreaddons for openSUSE:Factory checked in at 2025-08-09 19:57:45 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kf6-kcoreaddons (Old) and /work/SRC/openSUSE:Factory/.kf6-kcoreaddons.new.1085 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kf6-kcoreaddons" Sat Aug 9 19:57:45 2025 rev:18 rq:1298530 version:6.17.0 Changes: -------- --- /work/SRC/openSUSE:Factory/kf6-kcoreaddons/kf6-kcoreaddons.changes 2025-07-14 10:52:40.427052357 +0200 +++ /work/SRC/openSUSE:Factory/.kf6-kcoreaddons.new.1085/kf6-kcoreaddons.changes 2025-08-09 20:02:46.809646388 +0200 @@ -1,0 +2,20 @@ +Mon Aug 4 06:57:24 UTC 2025 - Christophe Marin <christo...@krop.fr> + +- Update to 6.17.0 + * New feature release + * For more details please see: + * https://kde.org/announcements/frameworks/6/6.17.0 +- Changes since 6.16.0: + * Update dependency version to 6.17.0 + * Require less precise timing in kformattest + * fix crash/stack overflow on drive removal on Windows (kde#499865) + * QStaticPlugin is a struct, no class + * widen the intervals + * fix jobtest on Windows + * Fix reading of localized JSON values on Windows (and macOS) + * It compiles fine without qt 6.10 deprecated methods + * [kpluginmetadata] Tweak docs + * Fix since version + * Update version to 6.17.0 + +------------------------------------------------------------------- Old: ---- kcoreaddons-6.16.0.tar.xz kcoreaddons-6.16.0.tar.xz.sig New: ---- kcoreaddons-6.17.0.tar.xz kcoreaddons-6.17.0.tar.xz.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kf6-kcoreaddons.spec ++++++ --- /var/tmp/diff_new_pack.AZp8W0/_old 2025-08-09 20:02:47.601679287 +0200 +++ /var/tmp/diff_new_pack.AZp8W0/_new 2025-08-09 20:02:47.605679454 +0200 @@ -1,7 +1,7 @@ # # spec file for package kf6-kcoreaddons # -# Copyright (c) 2025 SUSE LLC +# Copyright (c) 2025 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -32,11 +32,11 @@ %define mypython_sitearch %{expand:%%%{mypython}_sitearch} %endif -# Full KF6 version (e.g. 6.16.0) +# Full KF6 version (e.g. 6.17.0) %{!?_kf6_version: %global _kf6_version %{version}} %bcond_without released Name: kf6-kcoreaddons -Version: 6.16.0 +Version: 6.17.0 Release: 0 Summary: Utilities for core application functionality and accessing the OS License: LGPL-2.1-or-later ++++++ kcoreaddons-6.16.0.tar.xz -> kcoreaddons-6.17.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcoreaddons-6.16.0/CMakeLists.txt new/kcoreaddons-6.17.0/CMakeLists.txt --- old/kcoreaddons-6.16.0/CMakeLists.txt 2025-07-04 18:46:34.000000000 +0200 +++ new/kcoreaddons-6.17.0/CMakeLists.txt 2025-08-01 12:30:52.000000000 +0200 @@ -1,10 +1,10 @@ cmake_minimum_required(VERSION 3.16) -set(KF_VERSION "6.16.0") # handled by release scripts +set(KF_VERSION "6.17.0") # handled by release scripts project(KCoreAddons VERSION ${KF_VERSION}) include(FeatureSummary) -find_package(ECM 6.16.0 NO_MODULE) +find_package(ECM 6.17.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) @@ -143,7 +143,7 @@ ecm_set_disabled_deprecation_versions( - QT 6.9.0 + QT 6.10.0 ) add_subdirectory(src) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcoreaddons-6.16.0/autotests/kdirwatch_unittest.cpp new/kcoreaddons-6.17.0/autotests/kdirwatch_unittest.cpp --- old/kcoreaddons-6.16.0/autotests/kdirwatch_unittest.cpp 2025-07-04 18:46:34.000000000 +0200 +++ new/kcoreaddons-6.17.0/autotests/kdirwatch_unittest.cpp 2025-08-01 12:30:52.000000000 +0200 @@ -78,6 +78,7 @@ void testRefcounting(); void testRelativeRefcounting(); void testMoveToThread(); + void testWindowsDriveRemoved(); protected Q_SLOTS: // internal slots void nestedEventLoopSlot(); @@ -719,8 +720,8 @@ // its entries with it regardless of whether the entry was well-formed KDirWatch watch0; - if (watch0.internalMethod() != KDirWatch::INotify) { - // Only test on inotify. Otherwise Entry count expectations may diverge. + if (watch0.internalMethod() != KDirWatch::INotify && watch0.internalMethod() != KDirWatch::QFSWatch) { + // Only test on inotify & QFileSystemWatcher. Otherwise Entry count expectations may diverge. return; } @@ -731,8 +732,10 @@ // NOTE: addFile actually adds two entires: one for '.' to watch for the appearance of the file and one for the file. QCOMPARE(watch0.d->m_mapEntries.size(), initialSize + 2); } - // NOTE: we leak the directory entry from above but it has no clients so it's mostly harmless - QCOMPARE(watch0.d->m_mapEntries.size(), initialSize + 1); + + // NOTE: we leak did the directory entry from above but, that was fixed with the use of QFileInfo(path).absolutePath(); + // in KDirWatchPrivate::Entry::parentDirectory() + QCOMPARE(watch0.d->m_mapEntries.size(), initialSize); } void KDirWatch_UnitTest::testMoveToThread() @@ -763,4 +766,22 @@ waitUntilMTimeChange(file); } +void KDirWatch_UnitTest::testWindowsDriveRemoved() +{ + // test that QDir::isRoot works as needed + // we use that in Entry::isRoot + // see KDirWatchPrivate::useQFSWatch & bug 499865 comment there +#ifdef Q_OS_WIN + QVERIFY(QDir(QLatin1String("Y://")).isRoot()); + QVERIFY(QDir(QLatin1String("Y:/")).isRoot()); + QVERIFY(QDir(QLatin1String("Y:\\")).isRoot()); + QVERIFY(QDir(QLatin1String("Y:\\\\")).isRoot()); + QVERIFY(!QDir(QLatin1String("Y:/a")).isRoot()); +#else + QVERIFY(QDir(QLatin1String("/")).isRoot()); + QVERIFY(QDir(QLatin1String("//")).isRoot()); + QVERIFY(!QDir(QLatin1String("/test")).isRoot()); +#endif +} + #include "kdirwatch_unittest.moc" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcoreaddons-6.16.0/autotests/kformattest.cpp new/kcoreaddons-6.17.0/autotests/kformattest.cpp --- old/kcoreaddons-6.16.0/autotests/kformattest.cpp 2025-07-04 18:46:34.000000000 +0200 +++ new/kcoreaddons-6.17.0/autotests/kformattest.cpp 2025-08-01 12:30:52.000000000 +0200 @@ -439,9 +439,9 @@ testDateTime = now.addSecs(1); QCOMPARE(format.formatRelativeDateTime(testDateTime, QLocale::NarrowFormat), "Now"_L1); - testDateTime = now.addSecs(-300); + testDateTime = QDateTime::currentDateTime().addSecs(-330); QCOMPARE(format.formatRelativeDateTime(testDateTime, QLocale::NarrowFormat), "5 min(s) ago"_L1); - testDateTime = now.addSecs(300); + testDateTime = QDateTime::currentDateTime().addSecs(310); QCOMPARE(format.formatRelativeDateTime(testDateTime, QLocale::NarrowFormat), "5 min(s)"_L1); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcoreaddons-6.16.0/autotests/kjobtest.cpp new/kcoreaddons-6.17.0/autotests/kjobtest.cpp --- old/kcoreaddons-6.16.0/autotests/kjobtest.cpp 2025-07-04 18:46:34.000000000 +0200 +++ new/kcoreaddons-6.17.0/autotests/kjobtest.cpp 2025-08-01 12:30:52.000000000 +0200 @@ -338,11 +338,12 @@ } QVERIFY(!job->isFinished()); - loop.processEvents(QEventLoop::AllEvents, 2000); - QCOMPARE(destroyed_spy.size(), autoDelete); - if (!autoDelete) { - QVERIFY(job->isFinished()); + if (autoDelete) { + QTRY_COMPARE_WITH_TIMEOUT(destroyed_spy.size(), 1, 5000); + } else { + QTRY_VERIFY_WITH_TIMEOUT(job->isFinished(), 5000); } + QCOMPARE(destroyed_spy.size(), autoDelete); QVERIFY(!actions.empty()); // The first action alone should determine the job's error and result. @@ -409,27 +410,27 @@ QSignalSpy suspended_spy(m_innerJob, &KJob::suspended); QSignalSpy resume_spy(m_innerJob, &KJob::resumed); - QTimer::singleShot(50, m_innerJob, [this]() { + QTimer::singleShot(500, m_innerJob, [this]() { m_innerJob->suspend(); - QCOMPARE_GE(m_innerJob->elapsedTime(), 50); - QCOMPARE_LE(m_innerJob->elapsedTime(), 80); + QCOMPARE_GE(m_innerJob->elapsedTime(), 400); + QCOMPARE_LE(m_innerJob->elapsedTime(), 600); }); - QTimer::singleShot(100, m_innerJob, &KJob::resume); + QTimer::singleShot(1000, m_innerJob, &KJob::resume); - QTimer::singleShot(150, m_innerJob, [this]() { + QTimer::singleShot(1500, m_innerJob, [this]() { m_innerJob->suspend(); - QCOMPARE_GE(m_innerJob->elapsedTime(), 100); - QCOMPARE_LE(m_innerJob->elapsedTime(), 140); + QCOMPARE_GE(m_innerJob->elapsedTime(), 900); + QCOMPARE_LE(m_innerJob->elapsedTime(), 1100); }); - QTimer::singleShot(200, m_innerJob, [this]() { + QTimer::singleShot(2000, m_innerJob, [this]() { m_innerJob->resume(); m_innerJob->makeItFinish(); }); QVERIFY(m_innerJob->exec()); - QCOMPARE_GE(m_innerJob->elapsedTime(), 100); - QCOMPARE_LE(m_innerJob->elapsedTime(), 140); + QCOMPARE_GE(m_innerJob->elapsedTime(), 900); + QCOMPARE_LE(m_innerJob->elapsedTime(), 1100); QCOMPARE(suspended_spy.count(), 2); QCOMPARE(resume_spy.count(), 2); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcoreaddons-6.16.0/autotests/plugin/CMakeLists.txt new/kcoreaddons-6.17.0/autotests/plugin/CMakeLists.txt --- old/kcoreaddons-6.16.0/autotests/plugin/CMakeLists.txt 2025-07-04 18:46:34.000000000 +0200 +++ new/kcoreaddons-6.17.0/autotests/plugin/CMakeLists.txt 2025-08-01 12:30:52.000000000 +0200 @@ -3,6 +3,10 @@ return() endif() +if (Qt6_VERSION VERSION_GREATER_EQUAL "6.10.0") + find_package(Qt6CorePrivate ${Qt6_VERSION} EXACT CONFIG REQUIRED) +endif() + add_library(plugin_classes plugins.cpp) generate_export_header(plugin_classes) @@ -33,6 +37,7 @@ ${autotests_OPTIONAL_SRCS} LINK_LIBRARIES Qt6::Test Qt6::Widgets KF6::CoreAddons autotests_static ) +target_link_libraries(kpluginmetadatatest Qt6::CorePrivate) if (NOT WIN32) target_link_libraries(kpluginfactorytest plugin_classes) endif() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcoreaddons-6.16.0/autotests/plugin/kpluginmetadatatest.cpp new/kcoreaddons-6.17.0/autotests/plugin/kpluginmetadatatest.cpp --- old/kcoreaddons-6.16.0/autotests/plugin/kpluginmetadatatest.cpp 2025-07-04 18:46:34.000000000 +0200 +++ new/kcoreaddons-6.17.0/autotests/plugin/kpluginmetadatatest.cpp 2025-08-01 12:30:52.000000000 +0200 @@ -19,6 +19,8 @@ #include <QLocale> #include <QLoggingCategory> +#include <private/qlocale_p.h> // QSystemLocale + class LibraryPathRestorer { public: @@ -173,6 +175,10 @@ void testTranslations() { + const auto restoreDefaultLocale = qScopeGuard([prior = QLocale()]() { + QLocale::setDefault(prior); + }); + QJsonParseError e; QJsonObject jo = QJsonDocument::fromJson( "{ \"KPlugin\": {\n" @@ -203,6 +209,39 @@ QCOMPARE(m.description(), QStringLiteral("Description")); } + void testTranslationsWithOverrideLanguage() + { + const auto restoreDefaultLocale = qScopeGuard([prior = QLocale()]() { + QLocale::setDefault(prior); + }); + + // simulate usage of language override (kxmlgui); + // we need to create a new QSystemLocale to make Qt update the locale + qputenv("LANGUAGE", "de_DE:fr_FR"); + QSystemLocale newSystemLocale{}; + + QJsonParseError e; + QJsonObject jo = QJsonDocument::fromJson( + "{ \"KPlugin\": {\n" + "\"Name\": \"Name\",\n" + "\"Name[de]\": \"Name (de)\",\n" + "\"Name[de_DE]\": \"Name (de_DE)\",\n" + "\"Description\": \"Description\",\n" + "\"Description[de]\": \"Beschreibung (de)\",\n" + "\"Description[de_DE]\": \"Beschreibung (de_DE)\"\n" + "}\n}", + &e) + .object(); + KPluginMetaData m(jo, QString()); + QCOMPARE(m.name(), QStringLiteral("Name (de_DE)")); + QCOMPARE(m.description(), QStringLiteral("Beschreibung (de_DE)")); + + // verify that manually set default locale is preferred + QLocale::setDefault(QLocale(QStringLiteral("de_CH"))); + QCOMPARE(m.name(), QStringLiteral("Name (de)")); + QCOMPARE(m.description(), QStringLiteral("Beschreibung (de)")); + } + void testReadStringList() { if (!doMessagesWork()) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcoreaddons-6.16.0/poqm/fi/kcoreaddons6_qt.po new/kcoreaddons-6.17.0/poqm/fi/kcoreaddons6_qt.po --- old/kcoreaddons-6.16.0/poqm/fi/kcoreaddons6_qt.po 2025-07-04 18:46:34.000000000 +0200 +++ new/kcoreaddons-6.17.0/poqm/fi/kcoreaddons6_qt.po 2025-08-01 12:30:52.000000000 +0200 @@ -26,7 +26,7 @@ "Project-Id-Version: kdelibs4\n" "Report-Msgid-Bugs-To: http://bugs.kde.org\n" "POT-Creation-Date: 2014-03-23 01:50+0000\n" -"PO-Revision-Date: 2025-05-28 17:10+0300\n" +"PO-Revision-Date: 2025-07-10 19:37+0300\n" "Last-Translator: Tommi Nieminen <transla...@legisign.org>\n" "Language-Team: Finnish <kde-i18n-...@kde.org>\n" "Language: fi\n" @@ -696,8 +696,8 @@ msgctxt "KFormat|" msgid "%n yr" msgid_plural "%n yr" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%n v" +msgstr[1] "%n v" #. @item:intext abbreviated amount of days #: lib/util/kformatprivate.cpp:338 @@ -856,15 +856,12 @@ #. @item:intext %n is a whole number #: lib/util/kformatprivate.cpp:508 -#, fuzzy, qt-format -#| msgctxt "KFormat|" -#| msgid "%n hour(s)" -#| msgid_plural "%n hour(s)" +#, qt-format msgctxt "KFormat|" msgid "%n year(s)" msgid_plural "%n year(s)" -msgstr[0] "%n tunti" -msgstr[1] "%n tuntia" +msgstr[0] "%n vuosi" +msgstr[1] "%n vuotta" #. @item:intext %n is a whole number #: lib/util/kformatprivate.cpp:513 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcoreaddons-6.16.0/poqm/hu/kcoreaddons6_qt.po new/kcoreaddons-6.17.0/poqm/hu/kcoreaddons6_qt.po --- old/kcoreaddons-6.16.0/poqm/hu/kcoreaddons6_qt.po 2025-07-04 18:46:34.000000000 +0200 +++ new/kcoreaddons-6.17.0/poqm/hu/kcoreaddons6_qt.po 2025-08-01 12:30:52.000000000 +0200 @@ -7,7 +7,7 @@ "Project-Id-Version: KDE 4.4\n" "Report-Msgid-Bugs-To: http://bugs.kde.org\n" "POT-Creation-Date: 2014-03-23 01:50+0000\n" -"PO-Revision-Date: 2025-01-30 10:37+0100\n" +"PO-Revision-Date: 2025-07-26 21:30+0200\n" "Last-Translator: Kristof Kiszel <ulys...@fsf.hu>\n" "Language-Team: Hungarian <kde-l10n...@kde.org>\n" "Language: hu\n" @@ -15,7 +15,7 @@ "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Lokalize 24.12.1\n" +"X-Generator: Lokalize 25.04.3\n" "X-Qt-Contexts: true\n" #: lib/io/kfilesystemtype.cpp:252 @@ -680,8 +680,8 @@ msgctxt "KFormat|" msgid "%n yr" msgid_plural "%n yr" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%n év" +msgstr[1] "%n év" #. @item:intext abbreviated amount of days #: lib/util/kformatprivate.cpp:338 @@ -840,15 +840,12 @@ #. @item:intext %n is a whole number #: lib/util/kformatprivate.cpp:508 -#, fuzzy, qt-format -#| msgctxt "KFormat|" -#| msgid "%n hour(s)" -#| msgid_plural "%n hour(s)" +#, qt-format msgctxt "KFormat|" msgid "%n year(s)" msgid_plural "%n year(s)" -msgstr[0] "%n óra" -msgstr[1] "%n óra" +msgstr[0] "%n év" +msgstr[1] "%n év" #. @item:intext %n is a whole number #: lib/util/kformatprivate.cpp:513 @@ -937,10 +934,7 @@ #. @item:intext %1 is a whole number, abbreviate minute value #: lib/util/kformatprivate.cpp:613 -#, fuzzy, qt-format -#| msgctxt "KFormat|" -#| msgid "%n minute(s) ago" -#| msgid_plural "%n minute(s) ago" +#, qt-format msgctxt "KFormat|" msgid "%n min(s) ago" msgid_plural "%n min(s) ago" @@ -957,18 +951,13 @@ msgstr[1] "%n perccel ezelőtt" #: lib/util/kformatprivate.cpp:623 -#, fuzzy -#| msgid "No" msgctxt "KFormat|" msgid "Now" -msgstr "Nem" +msgstr "Most" #. @item:intext %1 is a whole number, abbreviate minute value #: lib/util/kformatprivate.cpp:628 -#, fuzzy, qt-format -#| msgctxt "KFormat|" -#| msgid "%n minute(s)" -#| msgid_plural "%n minute(s)" +#, qt-format msgctxt "KFormat|" msgid "%n min(s)" msgid_plural "%n min(s)" @@ -977,15 +966,12 @@ #. @item:intext %1 is a whole number #: lib/util/kformatprivate.cpp:633 -#, fuzzy, qt-format -#| msgctxt "KFormat|" -#| msgid "%n minute(s)" -#| msgid_plural "%n minute(s)" +#, qt-format msgctxt "KFormat|" msgid "In %n minute(s)" msgid_plural "In %n minute(s)" -msgstr[0] "%n perc" -msgstr[1] "%n perc" +msgstr[0] "%n perc múlva" +msgstr[1] "%n perc múlva" #. relative datetime with %1 result of QLocale.toString(date, format) or formatRelativeDate and %2 result of QLocale.toString(time, timeformatType) If this does not fit the grammar of your language please contact the i18n team to solve the problem #: lib/util/kformatprivate.cpp:648 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcoreaddons-6.16.0/poqm/ko/kcoreaddons6_qt.po new/kcoreaddons-6.17.0/poqm/ko/kcoreaddons6_qt.po --- old/kcoreaddons-6.16.0/poqm/ko/kcoreaddons6_qt.po 2025-07-04 18:46:34.000000000 +0200 +++ new/kcoreaddons-6.17.0/poqm/ko/kcoreaddons6_qt.po 2025-08-01 12:30:52.000000000 +0200 @@ -8,7 +8,7 @@ "Project-Id-Version: kdelibs4\n" "Report-Msgid-Bugs-To: http://bugs.kde.org\n" "POT-Creation-Date: 2014-03-23 01:50+0000\n" -"PO-Revision-Date: 2025-06-10 23:53+0200\n" +"PO-Revision-Date: 2025-07-21 00:58+0200\n" "Last-Translator: Shinjo Park <k...@peremen.name>\n" "Language-Team: Korean <kde...@kde.org>\n" "Language: ko\n" @@ -679,7 +679,7 @@ msgctxt "KFormat|" msgid "%n yr" msgid_plural "%n yr" -msgstr[0] "" +msgstr[0] "%n년" #. @item:intext abbreviated amount of days #: lib/util/kformatprivate.cpp:338 @@ -833,14 +833,11 @@ #. @item:intext %n is a whole number #: lib/util/kformatprivate.cpp:508 -#, fuzzy, qt-format -#| msgctxt "KFormat|" -#| msgid "%n hour(s)" -#| msgid_plural "%n hour(s)" +#, qt-format msgctxt "KFormat|" msgid "%n year(s)" msgid_plural "%n year(s)" -msgstr[0] "%n시간" +msgstr[0] "%n년" #. @item:intext %n is a whole number #: lib/util/kformatprivate.cpp:513 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcoreaddons-6.16.0/src/lib/io/kdirwatch.cpp new/kcoreaddons-6.17.0/src/lib/io/kdirwatch.cpp --- old/kcoreaddons-6.16.0/src/lib/io/kdirwatch.cpp 2025-07-04 18:46:34.000000000 +0200 +++ new/kcoreaddons-6.17.0/src/lib/io/kdirwatch.cpp 2025-08-01 12:30:52.000000000 +0200 @@ -305,13 +305,17 @@ e->wd = -1; e->m_ctime = invalid_ctime; emitEvent(e, Deleted); - // If the parent dir was already watched, tell it something changed - Entry *parentEntry = entry(e->parentDirectory()); - if (parentEntry) { - parentEntry->dirty = true; + + // don't walk up over / or drives + if (!e->isRoot()) { + // If the parent dir was already watched, tell it something changed + Entry *parentEntry = entry(e->parentDirectory()); + if (parentEntry) { + parentEntry->dirty = true; + } + // Add entry to parent dir to notice if the entry gets recreated + addEntry(nullptr, e->parentDirectory(), e, true /*isDir*/); } - // Add entry to parent dir to notice if the entry gets recreated - addEntry(nullptr, e->parentDirectory(), e, true /*isDir*/); } if (event->mask & IN_IGNORED) { // Causes bug #207361 with kernels 2.6.31 and 2.6.32! @@ -508,9 +512,14 @@ return clients; } +bool KDirWatchPrivate::Entry::isRoot() const +{ + return QDir(path).isRoot(); +} + QString KDirWatchPrivate::Entry::parentDirectory() const { - return QDir::cleanPath(path + QLatin1String("/..")); + return QFileInfo(path).absolutePath(); } QList<const KDirWatchPrivate::Client *> KDirWatchPrivate::Entry::clientsForFileOrDir(const QString &tpath, bool *isDir) const @@ -675,6 +684,11 @@ e->m_mode = INotifyMode; if (e->m_status == NonExistent) { + // be safe, don't walk upwards on / + if (e->isRoot()) { + return false; + } + addEntry(nullptr, e->parentDirectory(), e, true); return true; } @@ -710,6 +724,14 @@ e->dirty = false; if (e->m_status == NonExistent) { + // be safe, don't walk upwards on drive level or / + // on e.g. Windows we can end up with a removed drive Y: + // parentDirectory() will then just keep looping with that, see bug 499865 + // just abort if we loop, is correct for all platforms + if (e->isRoot()) { + return false; + } + addEntry(nullptr, e->parentDirectory(), e, true /*isDir*/); return true; } @@ -1023,11 +1045,7 @@ removeWatch(e); } else { // Removed a NonExistent entry - we just remove it from the parent - if (e->isDir) { - removeEntry(nullptr, e->parentDirectory(), e); - } else { - removeEntry(nullptr, QFileInfo(e->path).absolutePath(), e); - } + removeEntry(nullptr, e->parentDirectory(), e); } if (e->m_mode == StatMode) { @@ -1453,7 +1471,11 @@ if (s_verboseDebug) { qCDebug(KDIRWATCH) << "scanEntry says" << entry->path << "was deleted"; } - addEntry(nullptr, entry->parentDirectory(), entry, true); + + // be safe, don't walk upwards on drive level or / + if (!entry->isRoot()) { + addEntry(nullptr, entry->parentDirectory(), entry, true); + } } else if (ev == Created) { if (s_verboseDebug) { qCDebug(KDIRWATCH) << "scanEntry says" << entry->path << "was created. wd=" << entry->wd; @@ -1604,10 +1626,9 @@ emitEvent(entry, ev); } if (ev == Deleted) { - if (entry->isDir) { + // be safe, don't walk upwards on drive level or / + if (!entry->isRoot()) { addEntry(nullptr, entry->parentDirectory(), entry, true); - } else { - addEntry(nullptr, QFileInfo(entry->path).absolutePath(), entry, true); } } else if (ev == Created) { // We were waiting for it to appear; now watch it diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcoreaddons-6.16.0/src/lib/io/kdirwatch_p.h new/kcoreaddons-6.17.0/src/lib/io/kdirwatch_p.h --- old/kcoreaddons-6.16.0/src/lib/io/kdirwatch_p.h 2025-07-04 18:46:34.000000000 +0200 +++ new/kcoreaddons-6.17.0/src/lib/io/kdirwatch_p.h 2025-08-01 12:30:52.000000000 +0200 @@ -118,7 +118,12 @@ int msecLeft, freq; bool isDir; + // is this already an entry for the root / or a full drive Y:? + bool isRoot() const; + + // go up one level QString parentDirectory() const; + void addClient(KDirWatch *, KDirWatch::WatchModes); void removeClient(KDirWatch *); int clientCount() const; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcoreaddons-6.16.0/src/lib/plugin/kpluginmetadata.h new/kcoreaddons-6.17.0/src/lib/plugin/kpluginmetadata.h --- old/kcoreaddons-6.16.0/src/lib/plugin/kpluginmetadata.h 2025-07-04 18:46:34.000000000 +0200 +++ new/kcoreaddons-6.17.0/src/lib/plugin/kpluginmetadata.h 2025-08-01 12:30:52.000000000 +0200 @@ -21,7 +21,7 @@ #include <functional> class QPluginLoader; -class QStaticPlugin; +struct QStaticPlugin; class KPluginMetaDataPrivate; class KAboutPerson; /*! @@ -266,7 +266,7 @@ * Reads the plugin metadata from a QPluginLoader instance. You must call QPluginLoader::setFileName() * or use the appropriate constructor on \a loader before calling this. * - * \a option Added in 6.0, see enum docs + * \a options Whether or not plugins without JSON metadata are considered valid. */ KPluginMetaData(const QPluginLoader &loader, KPluginMetaDataOptions options = {}); @@ -276,6 +276,8 @@ * Platform-specific library suffixes may be omitted since \a file will be resolved * using the same logic as QPluginLoader. * + * \a options Whether or not plugins without JSON metadata are considered valid. + * * \sa QPluginLoader::setFileName() */ KPluginMetaData(const QString &pluginFile, KPluginMetaDataOptions options = {}); @@ -318,25 +320,25 @@ * * \a pluginId The Id of the plugin. The id should be the same as the filename, see KPluginMetaData::pluginId() * - * \a option Added in 6.0, see enum docs + * \a options Whether or not plugins without JSON metadata are considered valid. * * \since 5.84 */ static KPluginMetaData findPluginById(const QString &directory, const QString &pluginId, KPluginMetaDataOptions options = {}); /*! - * Find all plugins inside \a directory. Only plugins which have JSON metadata will be considered. + * Find all plugins inside \a directory that satisfy a filter. * * \a directory The directory to search for plugins. If a relative path is given for \a directory, * all entries of QCoreApplication::libraryPaths() will be checked with \a directory appended as a * subdirectory. If an absolute path is given only that directory will be searched. * * \a filter a callback function that returns \c true if the found plugin should be loaded - * and \c false if it should be skipped. If this argument is omitted all plugins will be loaded + * and \c false if it should be skipped. If this argument is omitted all plugins will be loaded. * - * \a option Weather or not allow plugins with empty metadata to be considered valid + * \a options Whether or not plugins without JSON metadata are considered valid. * - * Returns all plugins found in \a directory that fulfil the constraints of \a filter + * Returns all plugins found in \a directory that fulfill the constraints of \a filter * \since 5.86 */ static QList<KPluginMetaData> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcoreaddons-6.16.0/src/lib/text/kjsonutils.cpp new/kcoreaddons-6.17.0/src/lib/text/kjsonutils.cpp --- old/kcoreaddons-6.16.0/src/lib/text/kjsonutils.cpp 2025-07-04 18:46:34.000000000 +0200 +++ new/kcoreaddons-6.17.0/src/lib/text/kjsonutils.cpp 2025-08-01 12:30:52.000000000 +0200 @@ -9,9 +9,29 @@ #include <QJsonObject> +static QString getDefaultLocaleName() +{ +#if defined(Q_OS_WIN) || defined(Q_OS_MAC) + if (QLocale() == QLocale::system()) { + // If the default locale hasn't been changed then + // On Windows and Apple OSs, we cannot use QLocale::system() if an application-specific + // language was set by kxmlgui because Qt ignores LANGUAGE on Windows and Apple OSs. + if (const auto firstLanguage = qEnvironmentVariable("LANGUAGE").section(u':', 0, 0, QString::SectionSkipEmpty); !firstLanguage.isEmpty()) { + return firstLanguage; + } + // Also prefer the configured display language over the system language + if (const auto languages = QLocale::system().uiLanguages(); !languages.isEmpty()) { + // uiLanguages() uses dashes as separator, but KConfig assumes underscores + return languages.value(0).replace(u'-', u'_'); + } + } +#endif + return QLocale().name(); +} + QJsonValue KJsonUtils::readTranslatedValue(const QJsonObject &jo, const QString &key, const QJsonValue &defaultValue) { - QString languageWithCountry = QLocale().name(); + QString languageWithCountry = getDefaultLocaleName(); auto it = jo.constFind(key + QLatin1Char('[') + languageWithCountry + QLatin1Char(']')); if (it != jo.constEnd()) { return it.value();